Difference between revisions of "MediaWiki:Gadget-calculator-drugs-core.js"

From WikiAnesthesia
Tag: Manual revert
 
(57 intermediate revisions by the same user not shown)
Line 3: Line 3:
  */
  */
( function() {
( function() {
    /**
     mw.calculators.setOptionValue( 'defaultDrugColor', 'default' );
    * DrugColor data
    mw.calculators.setOptionValue( 'defaultDrugPopulation', 'general' );
    */
    mw.calculators.setOptionValue( 'defaultDrugRoute', 'iv' );
     mw.calculators.addDrugColors( {
 
        anticholinergic: {
    mw.calculators.isValueDependent = function( value, variableId ) {
            primaryColor: '#9fc96b'
         // This may need generalized to support other variables in the future
        },
         if( variableId === 'weight' ) {
        benzodiazepine: {
             return value && value.formatUnits().match( /\/[\s(]*?kg/ );
            primaryColor: '#f57921'
         } else {
        },
             throw new Error( 'Dependence "' + variableId + '" not supported by isValueDependent' );
        benzodiazepineReversal: {
            parentColor: 'benzodiazepine',
            striped: true
        },
        cardiovascularAgonist: {
            primaryColor: '#e1c9df'
        },
        cardiovascularAntagonist: {
            parentColor: 'cardiovascularAgonist',
            striped: true
        },
        default: {
            primaryColor: '#fff',
            highlightColor: '#fff'
        },
        desflurane: {
            primaryColor: '#0072ae'
        },
        enflurane: {
            primaryColor: '#f9a23b'
        },
        epinephrine: {
            parentColor: 'cardiovascularAgonist',
            highlightColor: '#000'
        },
        halothane: {
            primaryColor: '#b20107'
         },
         isoflurane: {
            primaryColor: '#92278f'
        },
        localAnesthetic: {
             primaryColor: '#b6b2a9'
         },
        neuromuscularBlocker: {
             primaryColor: '#f15563'
        },
        neuromuscularBlockerReversal: {
            parentColor: 'neuromuscularBlocker',
            striped: true
        },
        nitrousOxide: {
            primaryColor: '#004f7c'
        },
        opioid: {
            primaryColor: '#6bc8ea'
        },
        opioidReversal: {
            parentColor: 'opioid',
            striped: true
        },
        sedativeHypnotic: {
            primaryColor: '#f7e20a'
        },
        sevoflurane: {
            primaryColor: '#ffe715'
        },
        succinylcholine: {
            parentColor: 'neuromuscularBlocker',
            highlightColor: '#000'
         }
         }
     } );
     };
 
 


     /**
     /**
     * DrugPopulation data
     * Define units
     */
     */
     mw.calculators.addDrugPopulations( {
     mw.calculators.addUnitsBases( {
         general: {
         concentration: {
             name: 'General',
             toString: function( units ) {
        },
                units = units.replace( 'pct', '%' );
        general120kg: {
                units = units.replace( 'ug', 'mcg' );
            name: 'General (≥120kg)',
 
            abbreviation: '≥120kg',
                 return units;
            variables: {
                weight: {
                    min: '120 kgwt'
                 }
             }
             }
         },
         },
         neonatal: {
         mass: {
             name: 'Neonatal',
             toString: function( units ) {
            variables: {
                 units = units.replace( 'ug', 'mcg' );
                 age: {
 
                    max: '0 yo'
                 return units;
                }
            }
        },
        pediatric: {
            name: 'Pediatric',
            variables: {
                age: {
                    min: '0 yo',
                    max: '17.9 yo'
                }
            }
        },
        geriatric: {
            name: 'Geriatric',
            variables: {
                age: {
                    min: '65 yo'
                 }
             }
             }
         }
         }
     } );
     } );


 
     mw.calculators.addUnits( {
 
         Eq: {
    /**
             baseName: 'mass_eq',
    * DrugRoute data
             prefixes: 'short'
    */
     mw.calculators.addDrugRoutes( {
         iv: {
             name: 'Intravenous',
             abbreviation: 'IV',
            default: true
         },
         },
         im: {
         mcg: {
             name: 'Intramuscular',
             baseName: 'mass',
             abbreviation: 'IM'
             definition: '1 ug'
         },
         },
         po: {
         patch: {
             name: 'Oral',
             baseName: 'volume_patch'
            abbreviation: 'PO'
         },
         },
         pr: {
         pct: {
             name: 'Rectal',
             baseName: 'concentration',
             abbreviation: 'PR'
             definition: '10 mg/mL',
        }
            formatValue: function( value ) {
    } );
                var pctMatch = value.match( /([\d.]+)\s*?%/ );


                if( pctMatch ) {
                    var pctValue = pctMatch[ 1 ];


                    value = pctValue + '% (' + 10 * pctValue + ' mg/mL)';
                }


    /**
                return value;
    * DrugIndication data
             }
    */
    mw.calculators.addDrugIndications( {
        abxProphylaxis: {
            name: 'Antimicrobial prophylaxis',
             abbreviation: 'Abx.'
         },
         },
         acls: {
         pill: {
             name: 'ACLS',
             baseName: 'volume_pill'
            abbreviation: 'ACLS'
         },
         },
         analgesia: {
         spray: {
             name: 'Analgesia',
             baseName: 'volume_spray'
            abbreviation: 'Analgesia'
         },
         },
         anaphylaxis: {
         units: {
             name: 'Anaphylaxis',
             baseName: 'mass_units',
             abbreviation: 'Anaphylaxis'
             aliases: [
        },
                'unit'
        anxiolysis: {
             ]
            name: 'Anxiolysis',
            abbreviation: 'Anxiety'
        },
        bradycardia: {
            name: 'Bradycardia',
            abbreviation: 'Bradycardia'
        },
        generalAnesthesia: {
             name: 'General anesthesia',
            abbreviation: 'GA'
        },
        hypotension: {
            name: 'Hypotension',
            abbreviation: 'Hypoten.'
        },
        hypocalcemia: {
            name: 'Hypocalcemia',
            abbreviation: 'Hypo Ca<sup>2+</sup>'
        },
        intubation: {
            name: 'Intubation',
            abbreviation: 'Intubation'
        },
        malignantHyperthermia: {
            name: 'Malignant hyperthermia',
            abbreviation: 'MH'
        },
        neuromuscularBlockade: {
            name: 'Neuromuscular blockade',
            abbreviation: 'NMB'
        },
        neuromuscularBlockadeReversal: {
            name: 'Neuromuscular blockade reversal',
            abbreviation: 'NMB reversal'
         },
         },
         mac: {
         vial: {
             name: 'Monitored anesthesia care',
             baseName: 'volume_vial'
            abbreviation: 'MAC'
        },
        ponv: {
            name: 'Postoperative nausea & vomiting',
            abbreviation: 'PONV'
        },
        tiva: {
            name: 'Total intravenous anesthesia',
            abbreviation: 'TIVA'
         }
         }
     } );
     } );
Line 221: Line 84:


     /**
     /**
     * Drug data
     * DrugColor
     */
     */
    mw.calculators.drugColors = {};


    mw.calculators.addDrugColors = function( drugColorData ) {
        var drugColors = mw.calculators.createCalculatorObjects( 'DrugColor', drugColorData );


        for( var drugColorId in drugColors ) {
            mw.calculators.drugColors[ drugColorId ] = drugColors[ drugColorId ];
        }
    };
    mw.calculators.getDrugColor = function( drugColorId ) {
        if( mw.calculators.drugColors.hasOwnProperty( drugColorId ) ) {
            return mw.calculators.drugColors[ drugColorId ];
        } else {
            return null;
        }
    };


     /**
     /**
     * Acetaminophen
     * Class DrugColor
    * @param {Object} propertyValues
    * @returns {mw.calculators.objectClasses.DrugColor}
    * @constructor
     */
     */
     mw.calculators.addDrugs( {
     mw.calculators.objectClasses.DrugColor = function( propertyValues ) {
         acetaminophen: {
         var properties = {
             name: 'Acetaminophen',
             required: [
            dosages: [
                 'id'
                 {
                    indication: 'analgesia',
                    population: 'general',
                    description: 'Max dose 4 g/day. Use caution in hepatic impairment.',
                    dose: {
                        dose: '1 g'
                    }
                }, {
                    indication: 'analgesia',
                    population: 'general',
                    route: 'po',
                    description: 'Max dose 4 g/day. Use caution in hepatic impairment.',
                    dose: {
                        min: '650 mg',
                        max: '1 g'
                    }
                }, {
                    indication: 'analgesia',
                    population: 'general',
                    route: 'pr',
                    description: 'Max dose 4 g/day. Use caution in hepatic impairment.',
                    dose: {
                        min: '650 mg',
                        max: '1 g'
                    }
                }, {
                    indication: 'analgesia',
                    population: 'pediatric',
                    description: 'Max 75 mg/kg/day or 4 g/day (whichever is less). Use caution in hepatic impairment.',
                    dose: {
                        dose: '15 mg/kg',
                        absoluteMax: '1 g'
                    }
                }, {
                    indication: 'analgesia',
                    population: 'pediatric',
                    route: 'po',
                    description: 'Max 75 mg/kg/day or 4 g/day (whichever is less). Use caution in hepatic impairment.',
                    dose: {
                        dose: '15 mg/kg',
                        absoluteMax: '1 g'
                    }
                }, {
                    indication: 'analgesia',
                    population: 'pediatric',
                    route: 'pr',
                    description: 'Max 100 mg/kg/day or 4 g/day (whichever is less). Use caution in hepatic impairment.',
                    references: [
                        'Patrick K. Birmingham, AF1-0567, Michael J. Tobin, Dennis M. Fisher, Thomas K. Henthorn, Steven C. Hall, Charles J. Coté; Initial and Subsequent Dosing of Rectal Acetaminophen in Children: A 24-Hour Pharmacokinetic Study of New Dose Recommendations. Anesthesiology 2001; 94:385–389 doi: https://doi.org/10.1097/00000542-200103000-00005'
                    ],
                    dose: [
                        {
                            name: 'Load',
                            dose: '40 mg/kg',
                            absoluteMax: '1 g'
                        }, {
                            name: 'Maintenance',
                            dose: '20 mg/kg',
                            absoluteMax: '1 g'
                        }
                    ]
                }
             ],
             ],
             preparations: [
             optional: [
                 {
                 'parentColor',
                    concentration: '10 mg/mL'
                'primaryColor',
                 }
                'highlightColor',
                 'striped'
             ]
             ]
        };
        mw.calculators.objectClasses.CalculatorObject.call( this, properties, propertyValues );
        this.parentColor = this.parentColor || this.id === mw.calculators.getOptionValue( 'defaultDrugColor' ) ? this.parentColor : mw.calculators.getOptionValue( 'defaultDrugColor' );
    };
    mw.calculators.objectClasses.DrugColor.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );
    mw.calculators.objectClasses.DrugColor.prototype.getParentDrugColor = function() {
        if( !this.parentColor ) {
            return null;
        }
        var parentDrugColor = mw.calculators.getDrugColor( this.parentColor );
        if( !parentDrugColor ) {
            throw new Error( 'Parent drug color "' + this.parentColor + '" not found for drug color "' + this.id + '"' );
        }
        return parentDrugColor;
    };
    mw.calculators.objectClasses.DrugColor.prototype.getHighlightColor = function() {
        if( this.highlightColor ) {
            return this.highlightColor;
        } else if( this.parentColor ) {
            return this.getParentDrugColor().getHighlightColor();
        }
    };
    mw.calculators.objectClasses.DrugColor.prototype.getPrimaryColor = function() {
        if( this.primaryColor ) {
            return this.primaryColor;
        } else if( this.parentColor ) {
            return this.getParentDrugColor().getPrimaryColor();
        }
    };
    mw.calculators.objectClasses.DrugColor.prototype.isStriped = function() {
        if( this.striped !== null ) {
            return this.striped;
        } else if( this.parentColor ) {
            return this.getParentDrugColor().isStriped();
         }
         }
     } );
     };
 
 






     /**
     /**
     * Atropine
     * DrugPopulation
     */
     */
     mw.calculators.addDrugs( [
 
        {
     mw.calculators.drugPopulations = {};
            id: 'atropine',
 
            name: 'Atropine',
    mw.calculators.addDrugPopulations = function( drugPopulationData ) {
            color: 'anticholinergic',
        var drugPopulations = mw.calculators.createCalculatorObjects( 'DrugPopulation', drugPopulationData );
            description: 'Low doses may cause paradoxical bradycardia',
 
            dosages: [
        for( var drugPopulationId in drugPopulations ) {
                {
            mw.calculators.drugPopulations[ drugPopulationId ] = drugPopulations[ drugPopulationId ];
                    indication: 'bradycardia',
        }
                    population: 'general',
    };
                    description: 'Repeat as needed to a maximum total dose of 3 mg',
 
                    dose: {
    mw.calculators.getDrugPopulation = function( drugPopulationId ) {
                        min: '0.5 mg',
        if( mw.calculators.drugPopulations.hasOwnProperty( drugPopulationId ) ) {
                        max: '1 mg',
             return mw.calculators.drugPopulations[ drugPopulationId ];
                        frequency: 'q3-5m'
        } else {
                    }
             return null;
                }, {
                    indication: 'bradycardia',
                    population: 'pediatric',
                    description: 'Repeat as needed to a maximum total dose of 1 mg',
                    dose: {
                        min: '10 mcg/kg',
                        max: '20 mcg/kg',
                        absoluteMin: '40 mcg',
                        frequency: 'q3-5m'
                    }
                }, {
                    indication: 'acls',
                    population: 'general',
                    description: 'Repeat as needed to a maximum total dose of 3 mg',
                    dose: {
                        dose: '1 mg',
                        frequency: 'q3-5m'
                    }
                }, {
                    indication: 'acls',
                    population: 'pediatric',
                    description: 'Repeat as needed to a maximum total dose of 1 mg',
                    dose: {
                        dose: '20 mcg/kg',
                        absoluteMin: '100 mcg',
                        absoluteMax: '500 mcg',
                        frequency: 'q3-5m'
                    }
                }
             ],
            preparations: [
                {
                    concentration: '0.1 mg/mL'
                }, {
                    concentration: '0.4 mg/mL',
                    default:true
                }
             ]
         }
         }
     ] );
     };






     /**
     /**
     * Calcium chloride
     * Class DrugPopulation
    * @param {Object} propertyValues
    * @returns {mw.calculators.objectClasses.DrugPopulation}
    * @constructor
     */
     */
     mw.calculators.addDrugs( [
     mw.calculators.objectClasses.DrugPopulation = function( propertyValues ) {
         {
         var properties = {
             id: 'calciumChloride',
             required: [
            name: 'Calcium chloride',
                'id',
            description: '<ul><li>Administer via central line</li><li>A 10 mL ampule of calcium chloride 100 mg/mL contains 272 mg of elemental calcium</li></ul>',
                 'name'
            references: [
                 'French S, Subauste J, Geraci S. Calcium abnormalities in hospitalized patients. South Med J. 2012 Apr;105(4):231-7. doi: 10.1097/SMJ.0b013e31824e1737. PMID: 22475676.'
             ],
             ],
             dosages: [
             optional: [
                 {
                 'abbreviation',
                    indication: 'hypocalcemia',
                'variables'
                    population: 'general',
            ]
                    dose: {
        };
                        min: '500 mg',
 
                        max: '1 g',
        mw.calculators.objectClasses.CalculatorObject.call( this, properties, propertyValues );
                        duration: '5-10 min'
 
                    }
        if( this.variables ) {
                }, {
            for( var variableId in this.variables ) {
                    indication: 'hypocalcemia',
                if( !mw.calculators.getVariable( variableId ) ) {
                    population: 'pediatric',
                    throw new Error( 'DrugPopulation variable "' + variableId + '" not defined' );
                    dose: {
                        min: '10 mg/kg',
                        max: '20 mg/kg',
                        absoluteMax: '1 g',
                        duration: '5-10 min'
                    }
                 }
                 }
            ],
 
            preparations: [
                this.variables[ variableId ].min = this.variables[ variableId ].hasOwnProperty( 'min' ) ?
                 {
                    math.unit( this.variables[ variableId ].min ) : null;
                     concentration: '100 mg/mL'
 
                 }
                 this.variables[ variableId ].max = this.variables[ variableId ].hasOwnProperty( 'max' ) ?
             ]
                     math.unit( this.variables[ variableId ].max ) : null;
            }
        } else {
            this.variables = {};
        }
    };
 
    mw.calculators.objectClasses.DrugPopulation.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );
 
    mw.calculators.objectClasses.DrugPopulation.prototype.getCalculationData = function() {
        var inputData = new mw.calculators.objectClasses.CalculationData();
 
        for( var variableId in this.variables ) {
            inputData.variables.required.push( variableId );
        }
 
        return inputData;
    };
 
    mw.calculators.objectClasses.DrugPopulation.prototype.getCalculationDataScore = function( dataValues ) {
        // A return value of -1 indicates the data did not match the population definition
 
        for( var variableId in this.variables ) {
            if( !dataValues.hasOwnProperty( variableId ) ) {
                return -1;
            }
 
            if( this.variables[ variableId ].min &&
                ( !dataValues[ variableId ] ||
                    !math.largerEq( dataValues[ variableId ], this.variables[ variableId ].min ) ) ) {
                 return -1;
            }
 
             if( this.variables[ variableId ].max &&
                ( !dataValues[ variableId ] ||
                    !math.smallerEq( dataValues[ variableId ], this.variables[ variableId ].max ) ) ) {
                return -1;
            }
         }
         }
     ] );
 
        // If the data matches the population definition, the score corresponds to the number of variables in the
        // population definition. This should roughly correspond to the specificity of the population.
        return Object.keys( this.variables ).length;
    };
 
     mw.calculators.objectClasses.DrugPopulation.prototype.toString = function() {
        return mw.calculators.isMobile() && this.abbreviation ? this.abbreviation : this.name;
    };






     /**
     /**
     * Calcium gluconate
     * DrugRoute
     */
     */
     mw.calculators.addDrugs( [
     mw.calculators.drugRoutes = {};
        {
 
            id: 'calciumGluconate',
    mw.calculators.addDrugRoutes = function( drugRouteData ) {
            name: 'Calcium gluconate',
        var drugRoutes = mw.calculators.createCalculatorObjects( 'DrugRoute', drugRouteData );
            description: '<ul><li>Can administer peripherally</li><li>A 10 mL ampule of calcium gluconate 100 mg/mL contains 93 mg of elemental calcium</li></ul>',
 
            references: [
        for( var drugRouteId in drugRoutes ) {
                'French S, Subauste J, Geraci S. Calcium abnormalities in hospitalized patients. South Med J. 2012 Apr;105(4):231-7. doi: 10.1097/SMJ.0b013e31824e1737. PMID: 22475676.'
             mw.calculators.drugRoutes[ drugRouteId ] = drugRoutes[ drugRouteId ];
            ],
            dosages: [
                {
                    indication: 'hypocalcemia',
                    population: 'general',
                    dose: {
                        min: '1 g',
                        max: '2 g',
                        duration: '5-10 min'
                    }
                }, {
                    indication: 'hypocalcemia',
                    population: 'pediatric',
                    dose: {
                        dose: '30 mg/kg',
                        absoluteMax: '2 g',
                        duration: '5-10 min'
                    }
                }
             ],
            preparations: [
                {
                    concentration: '100 mg/mL'
                }
            ]
         }
         }
     ] );
     };
 


    mw.calculators.getDrugRoute = function( drugRouteId ) {
        if( mw.calculators.drugRoutes.hasOwnProperty( drugRouteId ) ) {
            return mw.calculators.drugRoutes[ drugRouteId ];
        } else {
            return null;
        }
    };


     /**
     /**
     * Cefazolin
     * Class DrugRoute
    * @param {Object} propertyValues
    * @returns {mw.calculators.objectClasses.DrugRoute}
    * @constructor
     */
     */
     mw.calculators.addDrugs( {
     mw.calculators.objectClasses.DrugRoute = function( propertyValues ) {
         cefazolin: {
         mw.calculators.objectClasses.CalculatorObject.call( this, this.getProperties(), propertyValues );
            name: 'Cefazolin',
 
            dosages: [
        this.abbreviation = this.abbreviation ? this.abbreviation : this.name;
                {
    };
                    indication: 'abxProphylaxis',
 
                    population: 'general',
    mw.calculators.objectClasses.DrugRoute.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );
                    dose: {
 
                        dose: '2 g',
    mw.calculators.objectClasses.DrugRoute.prototype.getProperties = function() {
                        frequency: 'q4h'
        return {
                    }
            required: [
                }, {
                 'id',
                    indication: 'abxProphylaxis',
                'name'
                    population: 'general120kg',
                    dose: {
                        dose: '3 g',
                        frequency: 'q4h'
                    }
                 }, {
                    indication: 'abxProphylaxis',
                    population: 'pediatric',
                    dose: {
                        dose: '30 mg/kg',
                        frequency: 'q4h'
                    }
                }
             ],
             ],
             preparations: [
             optional: [
                 {
                 'abbreviation',
                    concentration: '1 g/vial'
                 'default'
                 }
             ]
             ]
         }
         };
     } );
     };
 
    mw.calculators.objectClasses.DrugRoute.prototype.toString = function() {
        return mw.calculators.isMobile() && this.abbreviation ? this.abbreviation : this.name;
    };
 
 
 
 






     /**
     /**
     * Cisatracurium
     * DrugIndication
     */
     */
     mw.calculators.addDrugs( {
     mw.calculators.drugIndications = {};
        cisatracurium: {
 
            name: 'Cisatracurium',
    mw.calculators.addDrugIndications = function( drugIndicationData ) {
            color: 'neuromuscularBlocker',
        var drugIndications = mw.calculators.createCalculatorObjects( 'DrugIndication', drugIndicationData );
            dosages: [
 
                {
        for( var drugIndicationId in drugIndications ) {
                    indication: 'neuromuscularBlockade',
            mw.calculators.drugIndications[ drugIndicationId ] = drugIndications[ drugIndicationId ];
                    population: 'general',
                    dose: {
                        dose: '0.2 mg/kg'
                    }
                }
            ],
            preparations: [
                {
                    concentration: '2 mg/mL'
                }, {
                    concentration: '20 mg/mL'
                }
            ]
         }
         }
     } );
     };
 


    mw.calculators.getDrugIndication = function( drugIndicationId ) {
        if( mw.calculators.drugIndications.hasOwnProperty( drugIndicationId ) ) {
            return mw.calculators.drugIndications[ drugIndicationId ];
        } else {
            return null;
        }
    };


     /**
     /**
     * Dantrolene
     * Class DrugIndication
    * @param {Object} propertyValues
    * @returns {mw.calculators.objectClasses.DrugIndication}
    * @constructor
     */
     */
     mw.calculators.addDrugs( {
     mw.calculators.objectClasses.DrugIndication = function( propertyValues ) {
         dantrolene: {
         mw.calculators.objectClasses.CalculatorObject.call( this, this.getProperties(), propertyValues );
            name: 'Dantrolene',
    };
            dosages: [
 
                {
    mw.calculators.objectClasses.DrugIndication.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );
                    indication: 'malignantHyperthermia',
 
                    population: 'general',
    mw.calculators.objectClasses.DrugIndication.prototype.getProperties = function() {
                    dose: {
        return {
                        dose: '2.5 mg/kg'
            required: [
                    },
                'id',
                    description: 'Repeat up to a cumulative dose of 10 mg/kg'
                'name'
                }
             ],
             ],
             preparations: [
             optional: [
                 {
                 'abbreviation',
                    concentration: '250 mg/vial'
                 'default',
                 }, {
                'searchData'
                    concentration: '20 mg/vial'
                }
             ]
             ]
         }
         };
     } );
    };
 
    mw.calculators.objectClasses.DrugIndication.prototype.getSearchString = function() {
        var searchString = this.name;
 
        searchString += this.abbreviation ? ' ' + this.abbreviation : '';
        searchString += this.searchData ? ' ' + this.searchData : '';
 
        return searchString.trim();
     };
 
    mw.calculators.objectClasses.DrugIndication.prototype.toString = function() {
        return mw.calculators.isMobile() && this.abbreviation ? this.abbreviation : this.name;
    };
 
 






     /**
     /**
     * Dexmedetomidine
     * Drug
     */
     */
     mw.calculators.addDrugs( {
    mw.calculators.drugs = {};
         dexmedetomidine: {
 
            name: 'Dexmedetomidine',
     mw.calculators.addDrugs = function( drugData ) {
            color: 'sedativeHypnotic',
         var drugs = mw.calculators.createCalculatorObjects( 'Drug', drugData );
            dosages: [
 
                {
        for( var drugId in drugs ) {
                    indication: 'mac',
            mw.calculators.drugs[ drugId ] = drugs[ drugId ];
                    population: 'general',
                    dose: [
                        {
                            name: 'Load',
                            dose: '1 mcg/kg',
                            duration: '10 min'
                        }, {
                            name: 'Maintenance',
                            min: '0.2 mcg/kg/hr',
                            max: '1 mcg/kg/hr'
                        }
                    ]
                }
            ],
            preparations: [
                {
                    concentration: '4 mcg/mL'
                }, {
                    concentration: '100 mcg/mL',
                    dilutionRequired: true
                }
            ]
         }
         }
     } );
     };
 
    mw.calculators.addDrugDosages = function( drugId, drugDosageData ) {
        var drug = mw.calculators.getDrug( drugId );


        if( !drug ) {
            throw new Error( 'DrugDosage references drug "' + drugId + '" which is not defined' );
        }


        drug.addDosages( drugDosageData );
    };


    /**
     mw.calculators.getDrug = function( drugId ) {
    * Dexamethasone
         if( mw.calculators.drugs.hasOwnProperty( drugId ) ) {
    */
             return mw.calculators.drugs[ drugId ];
     mw.calculators.addDrugs( [
        } else {
         {
             return null;
             id: 'dexamethasone',
            name: 'Dexamethasone',
            dosages: [
                {
                    indication: 'ponv',
                    population: 'general',
                    dose: {
                        min: '4 mg',
                        max: '8 mg'
                    }
                }, {
                    indication: 'ponv',
                    population: 'pediatric',
                    dose: {
                        dose: '0.1 mg/kg',
                        absoluteMax: '10 mg'
                    }
                }
            ],
             preparations: [
                {
                    concentration: '2 mg/mL'
                }
            ]
         }
         }
     ] );
     };






     /**
     /**
     * Dobutamine
     * Class Drug
    * @param {Object} propertyValues
    * @returns {mw.calculators.objectClasses.Drug}
    * @constructor
     */
     */
     mw.calculators.addDrugs( {
     mw.calculators.objectClasses.Drug = function( propertyValues ) {
         dobutamine: {
         mw.calculators.objectClasses.CalculatorObject.call( this, this.getProperties(), propertyValues );
            name: 'Dobutamine',
 
            color: 'cardiovascularAgonist',
        if( !this.color ) {
            description: 'First line vasopressor for cardiogenic shock with low cardiac output and maintained blood pressure',
            this.color = mw.calculators.getOptionValue( 'defaultDrugColor' );
            dosages: [
        }
                {
 
                    indication: 'hypotension',
        var color = mw.calculators.getDrugColor( this.color );
                    population: 'general',
 
                    references: [
        if( !color ) {
                        'Hollenberg SM. Vasoactive drugs in circulatory shock. Am J Respir Crit Care Med. 2011 Apr 1;183(7):847-55. doi: 10.1164/rccm.201006-0972CI. Epub 2010 Nov 19. PMID: 21097695.'
            throw new Error( 'Invalid drug color "' + this.color + '" for drug "' + this.id + '"' );
                    ],
                    dose: {
                        min: '0.5 mcg/kg/min',
                        max: '20 mcg/kg/min'
                    }
                }
            ],
            preparations: [
                {
                    concentration: '0.5 mg/mL'
                }, {
                    concentration: '12.5 mg/mL'
                }
            ]
         }
         }
    } );


        this.color = color;
        if( this.preparations ) {
            var preparationData = this.preparations;


            this.preparations = [];


    /**
             this.addPreparations( preparationData );
    * Dopamine
        } else {
    */
             this.preparations = [];
    mw.calculators.addDrugs( {
        dopamine: {
            name: 'Dopamine',
            color: 'cardiovascularAgonist',
             description: '<ul><li>Predominant receptor activation is dose-dependent:<ul><li><5 mcg/kg/min: Dopaminergic</li><li>5-10 mcg/kg/min: &beta;-1 adrenergic</li><li>>10 mcg/kg/min: &alpha;-1 adrenergic</li></ul></li><li>Low-dose dopamine should not be used for renal protective effect</li></ul>',
            dosages: [
                {
                    indication: 'hypotension',
                    population: 'general',
                    references: [
                        'Hollenberg SM. Vasoactive drugs in circulatory shock. Am J Respir Crit Care Med. 2011 Apr 1;183(7):847-55. doi: 10.1164/rccm.201006-0972CI. Epub 2010 Nov 19. PMID: 21097695.',
                        'Bellomo R, Chapman M, Finfer S, Hickling K, Myburgh J. Low-dose dopamine in patients with early renal dysfunction: a placebo-controlled randomised trial. Australian and New Zealand Intensive Care Society (ANZICS) Clinical Trials Group. Lancet. 2000 Dec 23-30;356(9248):2139-43. doi: 10.1016/s0140-6736(00)03495-4. PMID: 11191541.'
                    ],
                    dose: {
                        min: '2 mcg/kg/min',
                        max: '50 mcg/kg/min'
                    }
                }, {
                    indication: 'hypotension',
                    population: 'pediatric',
                    dose: {
                        min: '5 mcg/kg/min',
                        max: '20 mcg/kg/min'
                    }
                }
            ],
             preparations: [
                {
                    concentration: '1.6 mg/mL'
                }, {
                    concentration: '40 mg/mL'
                }
            ]
         }
         }
    } );


        if( this.dosages ) {
            var dosageData = this.dosages;


            this.dosages = [];


    /**
            this.addDosages( dosageData );
    * Ephedrine
         } else {
    */
             this.dosages = [];
    mw.calculators.addDrugs( {
         ephedrine: {
             name: 'Ephedrine',
            color: 'cardiovascularAgonist',
            dosages: [
                {
                    indication: 'hypotension',
                    population: 'general',
                    dose: {
                        min: '2.5 mg',
                        max: '25 mg'
                    }
                }, {
                    indication: 'hypotension',
                    population: 'general',
                    route: 'im',
                    dose: {
                        min: '25 mg',
                        max: '50 mg'
                    }
                }, {
                    indication: 'hypotension',
                    population: 'pediatric',
                    dose: {
                        min: '0.02 mg/kg',
                        max: '0.2 mg/kg'
                    }
                }
            ],
            preparations: [
                {
                    concentration: '5 mg/mL'
                }, {
                    concentration: '50 mg/mL'
                }
            ]
         }
         }
    } );


        this.references = this.references ? mw.calculators.prepareReferences( this.references ) : [];
        this.tradeNames = this.tradeNames ? this.tradeNames : [];
    };
    mw.calculators.objectClasses.Drug.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );
    mw.calculators.objectClasses.Drug.prototype.addDosages = function( dosageData ) {
        var dosages = mw.calculators.createCalculatorObjects( 'DrugDosage', dosageData );


        for( var dosageId in dosages ) {
            dosages[ dosageId ].id = this.dosages.length;


    /**
            this.dosages.push( dosages[ dosageId ] );
    * Epinephrine
    */
    mw.calculators.addDrugs( {
        epinephrine: {
            name: 'Epinephrine',
            color: 'epinephrine',
            description: 'First line vasopressor for anaphylactic shock',
            dosages: [
                {
                    indication: 'hypotension',
                    population: 'general',
                    references: [
                        'Hollenberg SM. Vasoactive drugs in circulatory shock. Am J Respir Crit Care Med. 2011 Apr 1;183(7):847-55. doi: 10.1164/rccm.201006-0972CI. Epub 2010 Nov 19. PMID: 21097695.'
                    ],
                    dose: [
                        {
                            name: 'Bolus',
                            min: '5 mcg',
                            max: '20 mcg',
                            frequency: 'q1-5m'
                        }, {
                            name: 'Infusion',
                            min: '0.01 mcg/kg/min',
                            max: '2 mcg/kg/min'
                        }
                    ]
                }, {
                    indication: 'hypotension',
                    population: 'pediatric',
                    references: [
                        'Marino BS, Tabbutt S, MacLaren G, Hazinski MF, Adatia I, Atkins DL, Checchia PA, DeCaen A, Fink EL, Hoffman GM, Jefferies JL, Kleinman M, Krawczeski CD, Licht DJ, Macrae D, Ravishankar C, Samson RA, Thiagarajan RR, Toms R, Tweddell J, Laussen PC; American Heart Association Congenital Cardiac Defects Committee of the Council on Cardiovascular Disease in the Young; Council on Clinical Cardiology; Council on Cardiovascular and Stroke Nursing; Council on Cardiovascular Surgery and Anesthesia; and Emergency Cardiovascular Care Committee. Cardiopulmonary Resuscitation in Infants and Children With Cardiac Disease: A Scientific Statement From the American Heart Association. Circulation. 2018 May 29;137(22):e691-e782. doi: 10.1161/CIR.0000000000000524. Epub 2018 Apr 23. PMID: 29685887.',
                        'Reiter PD, Roth J, Wathen B, LaVelle J, Ridall LA. Low-Dose Epinephrine Boluses for Acute Hypotension in the PICU. Pediatr Crit Care Med. 2018 Apr;19(4):281-286. doi: 10.1097/PCC.0000000000001448. PMID: 29319635.'
                    ],
                    dose: [
                        {
                            name: 'Bolus',
                            min: '1 mcg/kg',
                            max: '5 mcg/kg',
                            frequency: 'q1-5m'
                        }, {
                            name: 'Infusion',
                            min: '0.02 mcg/kg/min',
                            max: '1 mcg/kg/min'
                        }
                    ]
                }, {
                    indication: 'acls',
                    population: 'general',
                    dose: {
                        dose: '1 mg',
                        frequency: 'q3-5m'
                    }
                }, {
                    indication: 'acls',
                    population: 'pediatric',
                    dose: {
                        dose: '10 mcg/kg',
                        absoluteMax: '1 mg',
                        frequency: 'q3-5m'
                    }
                }, {
                    indication: 'anaphylaxis',
                    population: 'general',
                    dose: [
                        {
                            name: 'Bolus',
                            dose: '10 mcg/kg',
                            absoluteMax: '0.5 mg',
                            frequency: 'q3-5m'
                        }, {
                            name: 'Infusion',
                            min: '0.1 mcg/kg/min',
                            max: '1 mcg/kg/min'
                        }
                    ]
                }, {
                    indication: 'anaphylaxis',
                    population: 'general',
                    route: 'im',
                    dose: {
                        dose: '10 mcg/kg',
                        frequency: 'q5-15m',
                        absoluteMax: '0.5 mg'
                    }
                }
            ],
            preparations: [
                {
                    concentration: '10 mcg/mL'
                }, {
                    concentration: '16 mcg/mL'
                }, {
                    concentration: '100 mcg/mL',
                    default: true
                }, {
                    concentration: '1 mg/mL'
                }
            ]
         }
         }
     } );
     };


    mw.calculators.objectClasses.Drug.prototype.addPreparations = function( preparationData ) {
        var preparations = mw.calculators.createCalculatorObjects( 'DrugPreparation', preparationData );


        for( var preparationId in preparations ) {
            preparations[ preparationId ].id = this.preparations.length;


     /**
            this.preparations.push( preparations[ preparationId ] );
    * Etomidate
        }
    */
     };
     mw.calculators.addDrugs( {
 
         etomidate: {
     mw.calculators.objectClasses.Drug.prototype.getIndications = function() {
            name: 'Etomidate',
         var indications = [];
            color: 'sedativeHypnotic',
 
             dosages: [
        for( var iDosage in this.dosages ) {
                {
             if( this.dosages[ iDosage ].indication ) {
                    indication: 'generalAnesthesia',
                indications.push( this.dosages[ iDosage ].indication );
                    population: 'general',
             }
                    dose: {
                        min: '0.2 mg/kg',
                        max: '0.6 mg/kg',
                        weightCalculation: [ 'lbw', 'ibw' ]
                    }
                }
            ],
             preparations: [
                {
                    concentration: '2 mg/mL'
                }
            ]
         }
         }
    } );


        return indications.filter( mw.calculators.uniqueValues );
    };


    mw.calculators.objectClasses.Drug.prototype.getPopulations = function( indicationId ) {
        var populations = [];


    /**
        for( var iDosage in this.dosages ) {
    * Ketamine
             if( this.dosages[ iDosage ].population &&
    */
                 ( !indicationId || ( this.dosages[ iDosage ].indication && this.dosages[ iDosage ].indication.id === indicationId ) ) ) {
    mw.calculators.addDrugs( {
                populations.push( this.dosages[ iDosage ].population );
        ketamine: {
             }
             name: 'Ketamine',
            color: 'sedativeHypnotic',
            dosages: [
                {
                    indication: 'generalAnesthesia',
                    population: 'general',
                    dose: {
                        min: '1 mg/kg',
                        max: '2 mg/kg',
                        weightCalculation: [ 'lbw', 'ibw'  ]
                    }
                }, {
                    indication: 'generalAnesthesia',
                    population: 'general',
                    route: 'im',
                    dose: {
                        min: '4 mg/kg',
                        max: '6 mg/kg'
                    }
                 }, {
                    indication: 'analgesia',
                    population: 'general',
                    description: 'To prevent prolonged recovery, do not administer in last hour of surgery.',
                    references: [
                        'Sabine Himmelseher, Marcel E. Durieux, Richard B. Weiskopf; Ketamine for Perioperative Pain Management. Anesthesiology 2005; 102:211–220 doi: https://doi.org/10.1097/00000542-200501000-00030'
                    ],
                    dose: [
                        {
                            name: 'Load (before incision)',
                            min: '0.25 mg/kg',
                            max: '0.5 mg/kg'
                        }, {
                            name: 'Maintenance',
                            min: '0.125 mg/kg',
                            max: '0.25 mg/kg',
                            frequency: 'q30m'
                        }
                    ]
                }
            ],
             preparations: [
                {
                    concentration: '10 mg/mL'
                }, {
                    concentration: '50 mg/mL'
                }, {
                    concentration: '100 mg/mL'
                }
            ]
         }
         }
    } );


        return populations.filter( mw.calculators.uniqueValues );
    };


    mw.calculators.objectClasses.Drug.prototype.getRoutes = function( indicationId ) {
        var routes = [];


    /**
        for( var iDosage in this.dosages ) {
    * Ketorolac
             if( this.dosages[ iDosage ].routes.length &&
    */
                 ( !indicationId || ( this.dosages[ iDosage ].indication && this.dosages[ iDosage ].indication.id === indicationId ) ) ) {
    mw.calculators.addDrugs( [
                 for( var iRoute in this.dosages[ iDosage ].routes ) {
        {
                     routes.push( this.dosages[ iDosage ].routes[ iRoute ] );
             id: 'ketorolac',
            name: 'Ketorolac',
            dosages: [
                 {
                    indication: 'analgesia',
                    population: 'general',
                    description: 'A 10 mg dose of ketorolac is as effective for acute pain control as a 15 or 30 mg dose<sup>1</sup>',
                    references: [
                        'Motov S, Yasavolian M, Likourezos A, Pushkar I, Hossain R, Drapkin J, Cohen V, Filk N, Smith A, Huang F, Rockoff B, Homel P, Fromm C. Comparison of Intravenous Ketorolac at Three Single-Dose Regimens for Treating Acute Pain in the Emergency Department: A Randomized Controlled Trial. Ann Emerg Med. 2017 Aug;70(2):177-184. doi: 10.1016/j.annemergmed.2016.10.014. Epub 2016 Dec 16. PMID: 27993418.'
                    ],
                    dose: {
                        min: '10 mg',
                        max: '30 mg'
                    }
                 }, {
                     indication: 'analgesia',
                    population: 'pediatric',
                    dose: {
                        min: '0.5 mg/kg',
                        max: '1 mg/kg',
                        absoluteMax: '30 mg'
                    }
                 }
                 }
             ],
             }
            preparations: [
                {
                    concentration: '15 mg/mL'
                }, {
                    concentration: '30 mg/mL',
                    default: true
                }
            ]
         }
         }
    ] );


        return routes.filter( mw.calculators.uniqueValues );
    };


    mw.calculators.objectClasses.Drug.prototype.getPreparations = function( excludeDilutionRequired ) {
        var preparations = this.preparations.filter( mw.calculators.uniqueValues );


    /**
        if( excludeDilutionRequired ) {
    * Lidocaine
            for( var iPreparation in preparations ) {
    */
                if( preparations[ iPreparation ].dilutionRequired ) {
    mw.calculators.addDrugs( {
                     delete preparations[ iPreparation ];
        lidocaine: {
            name: 'Lidocaine',
            color: 'localAnesthetic',
            dosages: [
                {
                     indication: 'intubation',
                    population: 'general',
                    dose: {
                        dose: '1 mg/kg'
                    }
                 }
                 }
            }
        }
        return preparations;
    };
    mw.calculators.objectClasses.Drug.prototype.getProperties = function() {
        return {
            required: [
                'id',
                'name'
             ],
             ],
             preparations: [
             optional: [
                 {
                 'color',
                    concentration: '1 pct'
                'description',
                 }, {
                'dosages',
                    concentration: '2 pct'
                'formula',
                 }
                'preparations',
                 'references',
                'searchData',
                 'tradeNames'
             ]
             ]
         }
         };
     } );
     };
 
 






     /**
     /**
     * Midazolam
     * DrugPreparation
     */
     */
     mw.calculators.addDrugs( {
     mw.calculators.addDrugPreparations = function( drugId, drugPreparationData ) {
         midazolam: {
         var drug = mw.calculators.getDrug( drugId );
            name: 'Midazolam',
 
            color: 'benzodiazepine',
        if( !drug ) {
            dosages: [
             throw new Error( 'DrugPreparation references drug "' + drugId + '" which is not defined' );
                {
                    indication: 'anxiolysis',
                    population: 'general',
                    dose: {
                        min: '0.01 mg/kg',
                        max: '0.03 mg/kg'
                    }
                }, {
                    indication: 'anxiolysis',
                    population: 'general',
                    route: 'im',
                    dose: {
                        min: '0.07 mg/kg',
                        max: '0.08 mg/kg'
                    }
                }, {
                    indication: 'anxiolysis',
                    population: 'general',
                    route: 'po',
                    dose: {
                        dose: '0.5 mg/kg',
                        absoluteMax: '20 mg'
                    }
                }, {
                    indication: 'generalAnesthesia',
                    population: 'general',
                    dose: {
                        min: '0.1 mg/kg',
                        max: '0.3 mg/kg',
                        weightCalculation: [ 'lbw', 'ibw' ]
                    }
                }
             ],
            preparations: [
                {
                    concentration: '1 mg/mL'
                }, {
                    concentration: '5 mg/mL'
                }
            ]
         }
         }
     } );
 
        drug.addPreparations( drugPreparationData );
     };






     /**
     /**
     * Milrinone
     * Class DrugPreparation
    * @param {Object} propertyValues
    * @returns {mw.calculators.objectClasses.DrugPreparation}
    * @constructor
     */
     */
     mw.calculators.addDrugs( {
     mw.calculators.objectClasses.DrugPreparation = function( propertyValues ) {
         milrinone: {
         var properties = {
             name: 'Milrinone',
             required: [
            color: 'cardiovascularAgonist',
                 'id',
            description: '<ul><li>Used in cardiogenic shock</li><li>Dose adjustment needed in renal impairment</li></ul>',
                'concentration'
            dosages: [
                 {
                    indication: 'hypotension',
                    population: 'general',
                    references: [
                        'Hollenberg SM. Vasoactive drugs in circulatory shock. Am J Respir Crit Care Med. 2011 Apr 1;183(7):847-55. doi: 10.1164/rccm.201006-0972CI. Epub 2010 Nov 19. PMID: 21097695.'
                    ],
                    dose: [
                        {
                            name: 'Load (optional)',
                            dose: '50 mcg/kg',
                            duration: '10 min'
                        }, {
                            name: 'Infusion',
                            min: '0.125 mcg/kg/min',
                            max: '0.75 mcg/kg/min'
                        }
                    ]
                }
             ],
             ],
             preparations: [
             optional: [
                 {
                 'default',
                    concentration: '0.2 mg/mL'
                 'dilutionRequired',
                 }, {
                'commonDilution'
                    concentration: '1 mg/mL'
                }
             ]
             ]
         }
         };
     } );
 
        mw.calculators.objectClasses.CalculatorObject.call( this, properties, propertyValues );
 
 
        this.concentration = this.concentration.replace( 'mcg', 'ug' );
 
        this.concentration = math.unit( this.concentration );
    };
 
    mw.calculators.objectClasses.DrugPreparation.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );
 
    mw.calculators.objectClasses.DrugPreparation.prototype.getVolumeUnits = function() {
        // The units of concentration will always be of the form "mass / volume"
        // The regular expression matches all text leading up to the volume units
        return mw.calculators.getUnitsByBase( this.concentration ).volume;
     };
 
    mw.calculators.objectClasses.DrugPreparation.prototype.toString = function() {
        return mw.calculators.getValueString( this.concentration );
    };
 
 






     /**
     /**
     * Neostigmine
     * Class DrugDosage
    * @param {Object} propertyValues
    * @returns {mw.calculators.objectClasses.DrugDosage}
    * @constructor
     */
     */
     mw.calculators.addDrugs( {
     mw.calculators.objectClasses.DrugDosage = function( propertyValues ) {
         neostigmine: {
         mw.calculators.objectClasses.CalculatorObject.call( this, this.getProperties(), propertyValues );
            name: 'Neostigmine',
 
            color: 'neuromuscularBlockerReversal',
        var drugIndication = mw.calculators.getDrugIndication( this.indication );
            dosages: [
 
                {
        if( !drugIndication ) {
                    indication: 'neuromuscularBlockadeReversal',
             throw new Error( 'Invalid indication "' + this.indication + '" for drug dosage' );
                    population: 'general',
                    description: 'For each 1 mg of neostigmine, give 0.2 mg of glycopyrrolate to avoid bradycardia',
                    dose: {
                        min: '0.03 mg/kg',
                        max: '0.07 mg/kg',
                        absoluteMax: '5 mg'
                    }
                }
             ],
            preparations: [
                {
                    concentration: '0.5 mg/mL'
                }, {
                    concentration: '1 mg/mL'
                }
            ]
         }
         }
    } );


        this.indication = drugIndication;
        this.population = this.population ? this.population : mw.calculators.getOptionValue( 'defaultDrugPopulation' );


        var drugPopulation = mw.calculators.getDrugPopulation( this.population );


    /**
        if( !drugPopulation ) {
    * Norepinephrine
             throw new Error( 'Invalid population "' + this.population + '" for drug dosage' );
    */
    mw.calculators.addDrugs( {
        norepinephrine: {
             name: 'Norepinephrine',
            color: 'cardiovascularAgonist',
            description: 'First line vasopressor for septic and hypovolemic shock',
            dosages: [
                {
                    indication: 'hypotension',
                    population: 'general',
                    references: [
                        'Hollenberg SM. Vasoactive drugs in circulatory shock. Am J Respir Crit Care Med. 2011 Apr 1;183(7):847-55. doi: 10.1164/rccm.201006-0972CI. Epub 2010 Nov 19. PMID: 21097695.'
                    ],
                    dose: [
                        {
                            name: 'Bolus',
                            min: '5 mcg',
                            max: '20 mcg'
                        }, {
                            name: 'Infusion',
                            min: '0.05 mcg/kg/min',
                            max: '3.3 mcg/kg/min'
                        }
                    ]
                }, {
                    indication: 'hypotension',
                    population: 'pediatric',
                    dose: [
                        {
                            name: 'Bolus',
                            min: '0.05 mcg/kg',
                            max: '0.1 mcg/kg'
                        }, {
                            name: 'Infusion',
                            min: '0.05 mcg/kg/min',
                            max: '2 mcg/kg/min'
                        }
                    ]
                }
            ],
            preparations: [
                {
                    concentration: '10 mcg/mL'
                }, {
                    concentration: '16 mcg/mL'
                }, {
                    concentration: '1 mg/mL',
                    dilutionRequired: true
                }
            ]
         }
         }
    } );


        this.population = drugPopulation;
        this.references = this.references ? mw.calculators.prepareReferences( this.references ) : [];


        this.routes = this.routes ? this.routes : [ mw.calculators.getOptionValue( 'defaultDrugRoute' ) ];


    /**
        if( !Array.isArray( this.routes ) ) {
    * Ondansetron
             this.routes = [ this.routes ];
    */
    mw.calculators.addDrugs( {
        ondansetron: {
             name: 'Ondansetron',
            dosages: [
                {
                    indication: 'ponv',
                    population: 'general',
                    dose: {
                        dose: '4 mg'
                    }
                }, {
                    indication: 'ponv',
                    population: 'pediatric',
                    dose: {
                        dose: '0.1 mg/kg',
                        absoluteMax: '4 mg'
                    }
                }
            ],
            preparations: [
                {
                    concentration: '2 mg/mL'
                }
            ]
         }
         }
    } );


        drugRoutes = [];
        for( var iRoute in this.routes ) {
            var drugRouteId = this.routes[ iRoute ];
            var drugRoute = mw.calculators.getDrugRoute( drugRouteId );


            if( !drugRoute ) {
                throw new Error( 'Invalid route "' + drugRouteId + '" for drug dosage' );
            }


    /**
             drugRoutes[ iRoute ] = drugRoute;
    * Phenylephrine
    */
    mw.calculators.addDrugs( {
        phenylephrine: {
             name: 'Phenylephrine',
            color: 'cardiovascularAgonist',
            dosages: [
                {
                    indication: 'hypotension',
                    population: 'general',
                    dose: [
                        {
                            name: 'Bolus',
                            min: '50 mcg',
                            max: '200 mcg'
                        }, {
                            name: 'Infusion',
                            min: '0.25 mcg/kg/min',
                            max: '1 mcg/kg/min'
                        }
                    ]
                }, {
                    indication: 'hypotension',
                    population: 'pediatric',
                    dose: [
                        {
                            name: 'Bolus',
                            min: '0.5 mcg/kg',
                            max: '1 mcg/kg'
                        }, {
                            name: 'Infusion',
                            min: '0.1 mcg/kg/min',
                            max: '0.5 mcg/kg/min'
                        }
                    ]
                }
            ],
            preparations: [
                {
                    concentration: '10 mcg/mL'
                }, {
                    concentration: '100 mcg/mL',
                    default: true
                }, {
                    concentration: '160 mcg/mL'
                }, {
                    concentration: '10 mg/mL',
                    dilutionRequired: true
                }
            ]
         }
         }
    } );


        this.routes = drugRoutes;
        // Add the dose objects to the drug
        var drugDoseData = this.dose;
        this.dose = [];
        this.addDoses( drugDoseData );
    };


    mw.calculators.objectClasses.DrugDosage.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );


    /**
     mw.calculators.objectClasses.DrugDosage.prototype.addDoses = function( drugDoseData ) {
    * Propofol
         if( !drugDoseData ) {
    */
             return;
     mw.calculators.addDrugs( {
        } else if( !Array.isArray( drugDoseData ) ) {
         propofol: {
            // Each dosage can have one or more associated doses. Ensure this value is an array.
             name: 'Propofol',
             drugDoseData = [ drugDoseData ];
            color: 'sedativeHypnotic',
            dosages: [
                {
                    indication: 'generalAnesthesia',
                    population: 'general',
                    dose: [
                        {
                            name: 'Induction',
                            min: '1 mg/kg',
                            max: '2.5 mg/kg',
                            weightCalculation: [ 'lbw', 'ibw' ]
                        }, {
                            name: 'Maintenance',
                            min: '100 mcg/kg/min',
                            max: '200 mcg/kg/min'
                        }
                    ]
                }, {
                    indication: 'generalAnesthesia',
                    population: 'pediatric',
                    dose: [
                        {
                            name: 'Induction',
                            min: '2.5 mg/kg',
                            max: '3.5 mg/kg',
                            weightCalculation: [ 'lbw', 'ibw' ]
                        }, {
                            name: 'Maintenance',
                            min: '125 mcg/kg/min',
                            max: '300 mcg/kg/min'
                        }
                    ]
                }, {
                    indication: 'generalAnesthesia',
                    population: 'geriatric',
                    dose: [
                        {
                            name: 'Induction',
                            min: '1 mg/kg',
                            max: '1.5 mg/kg',
                            weightCalculation: [ 'lbw', 'ibw' ]
                        }, {
                            name: 'Maintenance',
                            min: '50 mcg/kg/min',
                            max: '100 mcg/kg/min'
                        }
                    ]
                }, {
                    indication: 'mac',
                    population: 'general',
                    dose: {
                        min: '25 mcg/kg/min',
                        max: '75 mcg/kg/min'
                    }
                }
            ],
             preparations: [
                {
                    concentration: '10 mg/mL'
                }
            ]
         }
         }
    } );


        var doses = mw.calculators.createCalculatorObjects( 'DrugDose', drugDoseData );


        for( var doseId in doses ) {
            doses[ doseId ].id = this.dose.length;


    /**
            this.dose.push( doses[ doseId ] );
    * Remifentanil
    */
    mw.calculators.addDrugs( {
        remifentanil: {
            name: 'Remifentanil',
            color: 'opioid',
            dosages: [
                {
                    indication: 'tiva',
                    population: 'general',
                    dose: [
                        {
                            name: 'Load',
                            min: '1 mcg/kg',
                            max: '2 mcg/kg',
                            weightCalculation: [ 'lbw', 'ibw' ]
                        }, {
                            name: 'Maintenance',
                            min: '0.1 mcg/kg/min',
                            max: '1 mcg/kg/min'
                        }
                    ]
                }
            ],
            preparations: [
                {
                    concentration: '50 mcg/mL'
                }, {
                    concentration: '1 mg/vial',
                    dilutionRequired: true
                }, {
                    concentration: '2 mg/vial',
                    dilutionRequired: true
                }
            ]
         }
         }
     } );
     };
 
    mw.calculators.objectClasses.DrugDosage.prototype.getCalculationData = function() {
        var inputData = new mw.calculators.objectClasses.CalculationData();
 
        inputData = inputData.merge( this.population.getCalculationData() );


        for( var iDose in this.dose ) {
            inputData = inputData.merge( this.dose[ iDose ].getCalculationData() );
        }


        return inputData;
    };


    /**
     mw.calculators.objectClasses.DrugDosage.prototype.getProperties = function() {
    * Rocuronium
         return {
    */
             required: [
     mw.calculators.addDrugs( {
                 'id'
         rocuronium: {
             name: 'Rocuronium',
            color: 'neuromuscularBlocker',
            dosages: [
                 {
                    indication: 'neuromuscularBlockade',
                    population: 'general',
                    dose: [
                        {
                            name: 'Standard',
                            dose: '0.6 mg/kg'
                        }, {
                            name: 'Rapid sequence',
                            dose: '1.2 mg/kg'
                        }
                    ]
                }
             ],
             ],
             preparations: [
             optional: [
                 {
                 'description',
                    concentration: '10 mg/mL'
                'dose',
                 }
                'indication',
                'population',
                'routes',
                 'references'
             ]
             ]
        };
    };
    mw.calculators.objectClasses.DrugDosage.prototype.getRouteString = function() {
        var routeString = '';
        for( var iRoute in this.routes ) {
            routeString += routeString ? '/' : '';
            routeString += this.routes[ iRoute ].abbreviation;
         }
         }
     } );
 
        return routeString;
     };
 
    mw.calculators.objectClasses.DrugDosage.prototype.hasInfo = function() {
        return this.description;
    };
 
 






     /**
     /**
     * Succinylcholine
     * Class DrugDose
    * @param {Object} propertyValues
    * @returns {mw.calculators.objectClasses.DrugDose}
    * @constructor
     */
     */
     mw.calculators.addDrugs( {
     mw.calculators.objectClasses.DrugDose = function( propertyValues ) {
         succinylcholine: {
         mw.calculators.objectClasses.CalculatorObject.call( this, this.getProperties(), propertyValues );
             name: 'Succinylcholine',
 
             color: 'succinylcholine',
        if( this.weightCalculation ) {
             dosages: [
             var weightCalculationIds = this.weightCalculation;
                 {
 
                    indication: 'neuromuscularBlockade',
             // weightCalculation property will contain references to the actual objects, so reinitialize
                    population: 'general',
             this.weightCalculation = [];
                    dose: {
 
                        min: '1 mg/kg',
            if( !Array.isArray( weightCalculationIds ) ) {
                        max: '1.5 mg/kg'
                 weightCalculationIds = [ weightCalculationIds ];
                    }
            }
                 }, {
 
                     indication: 'neuromuscularBlockade',
            for( var iWeightCalculation in weightCalculationIds ) {
                    population: 'general',
                var weightCalculationId = weightCalculationIds[ iWeightCalculation ];
                    route: 'im',
                var weightCalculation = mw.calculators.getCalculation( weightCalculationId );
                    dose: {
 
                        min: '3 mg/kg',
                 if( !weightCalculation ) {
                        max: '5 mg/kg'
                     throw new Error( 'Drug dose references weight calculation "' + weightCalculationId + '" which is not defined' );
                    }
                 }
                 }
            ],
 
            preparations: [
                 this.weightCalculation.push( weightCalculation );
                 {
            }
                    concentration: '20 mg/mL'
        } else {
                }, {
             this.weightCalculation = [];
                    concentration: '100 mg/mL'
                }
             ]
         }
         }
    } );


        var mathProperties = this.getMathProperties();
        var isWeightDependent = false;
        for( var iMathProperty in mathProperties ) {
            var mathProperty = mathProperties[ iMathProperty ];
            if( this[ mathProperty ] ) {
                // TODO consider making a UnitsBase.weight.fromString()
                this[ mathProperty ] = this[ mathProperty ].replace( 'kg', 'kgwt' );
                this[ mathProperty ] = this[ mathProperty ].replace( 'mcg', 'ug' );


                this[ mathProperty ] = math.unit( this[ mathProperty ] );


    /**
                if( mw.calculators.isValueDependent( this[ mathProperty ], 'weight' ) ) {
    * Sufentanil
                     isWeightDependent = true;
    */
    mw.calculators.addDrugs( {
        sufentanil: {
            name: 'Sufentanil',
            color: 'opioid',
            dosages: [
                {
                    indication: 'tiva',
                    population: 'general',
                    dose: [
                        {
                            name: 'Load',
                            min: '0.25 mcg/kg',
                            max: '2 mcg/kg',
                            weightCalculation: [ 'lbw', 'ibw' ]
                        }, {
                            name: 'Maintenance',
                            min: '0.5 mcg/kg/hr',
                            max: '1.5 mcg/kg/hr'
                        }
                     ]
                 }
                 }
             ],
             } else {
             preparations: [
                this[ mathProperty ] = null;
                {
             }
                    concentration: '5 mcg/mL'
        }
                }, {
 
                    concentration: '50 mcg/mL'
        if( isWeightDependent ) {
                }
            // Default is tbw
             ]
             this.weightCalculation.push( mw.calculators.getCalculation( 'tbw' ) );
         }
         }
     } );
     };


    mw.calculators.objectClasses.DrugDose.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );


    mw.calculators.objectClasses.DrugDose.prototype.getAdministration = function() {
        var administration = '';


    /**
        if( this.frequency ) {
    * Sugammadex
             administration += administration ? ' ' : '';
    */
             administration += this.frequency;
    mw.calculators.addDrugs( {
        }
        sugammadex: {
 
             name: 'Sugammadex',
        if( this.duration ) {
            color: 'neuromuscularBlockerReversal',
            administration += administration ? ' ' : '';
             dosages: [
             administration += 'over ' + this.duration;
                {
                    indication: 'neuromuscularBlockadeReversal',
                    population: 'general',
                    description: '<ul><li>&ge;2 twitches on TOF: 2 mg/kg</li><li>1-2 posttetanic twitches: 4 mg/kg</li><li>Immediate reversal: 16 mg/kg</li></ul>',
                    dose: {
                        min: '2 mg/kg',
                        max: '16 mg/kg'
                    }
                }
            ],
             preparations: [
                {
                    concentration: '100 mg/mL'
                }
            ]
         }
         }
    } );


        return administration;
    };


    mw.calculators.objectClasses.DrugDose.prototype.getCalculationData = function() {
        var calculationData = new mw.calculators.objectClasses.CalculationData();


    /**
        for( var iWeightCalculation in this.weightCalculation ) {
    * Vasopressin
             calculationData.calculations.optional.push( this.weightCalculation[ iWeightCalculation ].id );
    */
    mw.calculators.addDrugs( {
        vasopressin: {
             name: 'Vasopressin',
            color: 'cardiovascularAgonist',
            dosages: [
                {
                    indication: 'hypotension',
                    population: 'general',
                    description: 'Use caution with sustained infusions >0.04 units/min which can cause cardiac and splanchnic ischemia',
                    references: [
                        'Hollenberg SM. Vasoactive drugs in circulatory shock. Am J Respir Crit Care Med. 2011 Apr 1;183(7):847-55. doi: 10.1164/rccm.201006-0972CI. Epub 2010 Nov 19. PMID: 21097695.'
                    ],
                    dose: [
                        {
                            name: 'Bolus',
                            min: '0.5 units',
                            max: '1 unit'
                        }, {
                            name: 'Infusion',
                            min: '0.01 units/min',
                            max: '0.07 units/min'
                        }
                    ]
                }, {
                    indication: 'hypotension',
                    population: 'pediatric',
                    references: [
                        'Choong K, Kissoon N. Vasopressin in pediatric shock and cardiac arrest. Pediatr Crit Care Med. 2008 Jul;9(4):372-9. doi: 10.1097/PCC.0b013e318172d7c8. PMID: 18496412.'
                    ],
                    dose: [
                        {
                            name: 'Bolus',
                            min: '0.005 units/kg',
                            max: '0.01 units/kg'
                        }, {
                            name: 'Infusion',
                            min: '0.0002 units/kg/min',
                            max: '0.008 units/kg/min'
                        }
                    ]
                }
            ],
            preparations: [
                {
                    concentration: '1 units/mL'
                }, {
                    concentration: '20 units/mL'
                }
            ]
         }
         }
    } );


        return calculationData;
    };


    mw.calculators.objectClasses.DrugDose.prototype.getMathProperties = function() {
        return [
            'dose',
            'min',
            'max',
            'absoluteMin',
            'absoluteMax'
        ];
    };


    /**
     mw.calculators.objectClasses.DrugDose.prototype.getProperties = function() {
    * Vecuronium
         return {
    */
             required: [
     mw.calculators.addDrugs( {
                 'id'
         vecuronium: {
             name: 'Vecuronium',
            color: 'neuromuscularBlocker',
            dosages: [
                 {
                    indication: 'neuromuscularBlockade',
                    population: 'general',
                    dose: [
                        {
                            name: 'Standard',
                            dose: '0.1 mg/kg'
                        }, {
                            name: 'Rapid sequence',
                            dose: '1.2 mg/kg'
                        }
                    ]
                }
             ],
             ],
             preparations: [
             optional: [
                 {
                 'absoluteMax',
                    concentration: '10 mg/vial'
                'absoluteMin',
                 }
                'dose',
                'duration',
                'frequency',
                'min',
                'max',
                'name',
                'text',
                 'weightCalculation'
             ]
             ]
         }
         };
     } );
     };
 
}() );
}() );

Latest revision as of 20:55, 29 March 2022

/**
 * @author Chris Rishel
 */
( function() {
    mw.calculators.setOptionValue( 'defaultDrugColor', 'default' );
    mw.calculators.setOptionValue( 'defaultDrugPopulation', 'general' );
    mw.calculators.setOptionValue( 'defaultDrugRoute', 'iv' );

    mw.calculators.isValueDependent = function( value, variableId ) {
        // This may need generalized to support other variables in the future
        if( variableId === 'weight' ) {
            return value && value.formatUnits().match( /\/[\s(]*?kg/ );
        } else {
            throw new Error( 'Dependence "' + variableId + '" not supported by isValueDependent' );
        }
    };

    /**
     * Define units
     */
    mw.calculators.addUnitsBases( {
        concentration: {
            toString: function( units ) {
                units = units.replace( 'pct', '%' );
                units = units.replace( 'ug', 'mcg' );

                return units;
            }
        },
        mass: {
            toString: function( units ) {
                units = units.replace( 'ug', 'mcg' );

                return units;
            }
        }
    } );

    mw.calculators.addUnits( {
        Eq: {
            baseName: 'mass_eq',
            prefixes: 'short'
        },
        mcg: {
            baseName: 'mass',
            definition: '1 ug'
        },
        patch: {
            baseName: 'volume_patch'
        },
        pct: {
            baseName: 'concentration',
            definition: '10 mg/mL',
            formatValue: function( value ) {
                var pctMatch = value.match( /([\d.]+)\s*?%/ );

                if( pctMatch ) {
                    var pctValue = pctMatch[ 1 ];

                    value = pctValue + '% (' + 10 * pctValue + ' mg/mL)';
                }

                return value;
            }
        },
        pill: {
            baseName: 'volume_pill'
        },
        spray: {
            baseName: 'volume_spray'
        },
        units: {
            baseName: 'mass_units',
            aliases: [
                'unit'
            ]
        },
        vial: {
            baseName: 'volume_vial'
        }
    } );



    /**
     * DrugColor
     */
    mw.calculators.drugColors = {};

    mw.calculators.addDrugColors = function( drugColorData ) {
        var drugColors = mw.calculators.createCalculatorObjects( 'DrugColor', drugColorData );

        for( var drugColorId in drugColors ) {
            mw.calculators.drugColors[ drugColorId ] = drugColors[ drugColorId ];
        }
    };

    mw.calculators.getDrugColor = function( drugColorId ) {
        if( mw.calculators.drugColors.hasOwnProperty( drugColorId ) ) {
            return mw.calculators.drugColors[ drugColorId ];
        } else {
            return null;
        }
    };

    /**
     * Class DrugColor
     * @param {Object} propertyValues
     * @returns {mw.calculators.objectClasses.DrugColor}
     * @constructor
     */
    mw.calculators.objectClasses.DrugColor = function( propertyValues ) {
        var properties = {
            required: [
                'id'
            ],
            optional: [
                'parentColor',
                'primaryColor',
                'highlightColor',
                'striped'
            ]
        };

        mw.calculators.objectClasses.CalculatorObject.call( this, properties, propertyValues );

        this.parentColor = this.parentColor || this.id === mw.calculators.getOptionValue( 'defaultDrugColor' ) ? this.parentColor : mw.calculators.getOptionValue( 'defaultDrugColor' );
    };

    mw.calculators.objectClasses.DrugColor.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );

    mw.calculators.objectClasses.DrugColor.prototype.getParentDrugColor = function() {
        if( !this.parentColor ) {
            return null;
        }

        var parentDrugColor = mw.calculators.getDrugColor( this.parentColor );

        if( !parentDrugColor ) {
            throw new Error( 'Parent drug color "' + this.parentColor + '" not found for drug color "' + this.id + '"' );
        }

        return parentDrugColor;
    };

    mw.calculators.objectClasses.DrugColor.prototype.getHighlightColor = function() {
        if( this.highlightColor ) {
            return this.highlightColor;
        } else if( this.parentColor ) {
            return this.getParentDrugColor().getHighlightColor();
        }
    };

    mw.calculators.objectClasses.DrugColor.prototype.getPrimaryColor = function() {
        if( this.primaryColor ) {
            return this.primaryColor;
        } else if( this.parentColor ) {
            return this.getParentDrugColor().getPrimaryColor();
        }
    };

    mw.calculators.objectClasses.DrugColor.prototype.isStriped = function() {
        if( this.striped !== null ) {
            return this.striped;
        } else if( this.parentColor ) {
            return this.getParentDrugColor().isStriped();
        }
    };





    /**
     * DrugPopulation
     */

    mw.calculators.drugPopulations = {};

    mw.calculators.addDrugPopulations = function( drugPopulationData ) {
        var drugPopulations = mw.calculators.createCalculatorObjects( 'DrugPopulation', drugPopulationData );

        for( var drugPopulationId in drugPopulations ) {
            mw.calculators.drugPopulations[ drugPopulationId ] = drugPopulations[ drugPopulationId ];
        }
    };

    mw.calculators.getDrugPopulation = function( drugPopulationId ) {
        if( mw.calculators.drugPopulations.hasOwnProperty( drugPopulationId ) ) {
            return mw.calculators.drugPopulations[ drugPopulationId ];
        } else {
            return null;
        }
    };



    /**
     * Class DrugPopulation
     * @param {Object} propertyValues
     * @returns {mw.calculators.objectClasses.DrugPopulation}
     * @constructor
     */
    mw.calculators.objectClasses.DrugPopulation = function( propertyValues ) {
        var properties = {
            required: [
                'id',
                'name'
            ],
            optional: [
                'abbreviation',
                'variables'
            ]
        };

        mw.calculators.objectClasses.CalculatorObject.call( this, properties, propertyValues );

        if( this.variables ) {
            for( var variableId in this.variables ) {
                if( !mw.calculators.getVariable( variableId ) ) {
                    throw new Error( 'DrugPopulation variable "' + variableId + '" not defined' );
                }

                this.variables[ variableId ].min = this.variables[ variableId ].hasOwnProperty( 'min' ) ?
                    math.unit( this.variables[ variableId ].min ) : null;

                this.variables[ variableId ].max = this.variables[ variableId ].hasOwnProperty( 'max' ) ?
                    math.unit( this.variables[ variableId ].max ) : null;
            }
        } else {
            this.variables = {};
        }
    };

    mw.calculators.objectClasses.DrugPopulation.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );

    mw.calculators.objectClasses.DrugPopulation.prototype.getCalculationData = function() {
        var inputData = new mw.calculators.objectClasses.CalculationData();

        for( var variableId in this.variables ) {
            inputData.variables.required.push( variableId );
        }

        return inputData;
    };

    mw.calculators.objectClasses.DrugPopulation.prototype.getCalculationDataScore = function( dataValues ) {
        // A return value of -1 indicates the data did not match the population definition

        for( var variableId in this.variables ) {
            if( !dataValues.hasOwnProperty( variableId ) ) {
                return -1;
            }

            if( this.variables[ variableId ].min &&
                ( !dataValues[ variableId ] ||
                    !math.largerEq( dataValues[ variableId ], this.variables[ variableId ].min ) ) ) {
                return -1;
            }

            if( this.variables[ variableId ].max &&
                ( !dataValues[ variableId ] ||
                    !math.smallerEq( dataValues[ variableId ], this.variables[ variableId ].max ) ) ) {
                return -1;
            }
        }

        // If the data matches the population definition, the score corresponds to the number of variables in the
        // population definition. This should roughly correspond to the specificity of the population.
        return Object.keys( this.variables ).length;
    };

    mw.calculators.objectClasses.DrugPopulation.prototype.toString = function() {
        return mw.calculators.isMobile() && this.abbreviation ? this.abbreviation : this.name;
    };



    /**
     * DrugRoute
     */
    mw.calculators.drugRoutes = {};

    mw.calculators.addDrugRoutes = function( drugRouteData ) {
        var drugRoutes = mw.calculators.createCalculatorObjects( 'DrugRoute', drugRouteData );

        for( var drugRouteId in drugRoutes ) {
            mw.calculators.drugRoutes[ drugRouteId ] = drugRoutes[ drugRouteId ];
        }
    };

    mw.calculators.getDrugRoute = function( drugRouteId ) {
        if( mw.calculators.drugRoutes.hasOwnProperty( drugRouteId ) ) {
            return mw.calculators.drugRoutes[ drugRouteId ];
        } else {
            return null;
        }
    };

    /**
     * Class DrugRoute
     * @param {Object} propertyValues
     * @returns {mw.calculators.objectClasses.DrugRoute}
     * @constructor
     */
    mw.calculators.objectClasses.DrugRoute = function( propertyValues ) {
        mw.calculators.objectClasses.CalculatorObject.call( this, this.getProperties(), propertyValues );

        this.abbreviation = this.abbreviation ? this.abbreviation : this.name;
    };

    mw.calculators.objectClasses.DrugRoute.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );

    mw.calculators.objectClasses.DrugRoute.prototype.getProperties = function() {
        return {
            required: [
                'id',
                'name'
            ],
            optional: [
                'abbreviation',
                'default'
            ]
        };
    };

    mw.calculators.objectClasses.DrugRoute.prototype.toString = function() {
        return mw.calculators.isMobile() && this.abbreviation ? this.abbreviation : this.name;
    };







    /**
     * DrugIndication
     */
    mw.calculators.drugIndications = {};

    mw.calculators.addDrugIndications = function( drugIndicationData ) {
        var drugIndications = mw.calculators.createCalculatorObjects( 'DrugIndication', drugIndicationData );

        for( var drugIndicationId in drugIndications ) {
            mw.calculators.drugIndications[ drugIndicationId ] = drugIndications[ drugIndicationId ];
        }
    };

    mw.calculators.getDrugIndication = function( drugIndicationId ) {
        if( mw.calculators.drugIndications.hasOwnProperty( drugIndicationId ) ) {
            return mw.calculators.drugIndications[ drugIndicationId ];
        } else {
            return null;
        }
    };

    /**
     * Class DrugIndication
     * @param {Object} propertyValues
     * @returns {mw.calculators.objectClasses.DrugIndication}
     * @constructor
     */
    mw.calculators.objectClasses.DrugIndication = function( propertyValues ) {
        mw.calculators.objectClasses.CalculatorObject.call( this, this.getProperties(), propertyValues );
    };

    mw.calculators.objectClasses.DrugIndication.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );

    mw.calculators.objectClasses.DrugIndication.prototype.getProperties = function() {
        return {
            required: [
                'id',
                'name'
            ],
            optional: [
                'abbreviation',
                'default',
                'searchData'
            ]
        };
    };

    mw.calculators.objectClasses.DrugIndication.prototype.getSearchString = function() {
        var searchString = this.name;

        searchString += this.abbreviation ? ' ' + this.abbreviation : '';
        searchString += this.searchData ? ' ' + this.searchData : '';

        return searchString.trim();
    };

    mw.calculators.objectClasses.DrugIndication.prototype.toString = function() {
        return mw.calculators.isMobile() && this.abbreviation ? this.abbreviation : this.name;
    };





    /**
     * Drug
     */
    mw.calculators.drugs = {};

    mw.calculators.addDrugs = function( drugData ) {
        var drugs = mw.calculators.createCalculatorObjects( 'Drug', drugData );

        for( var drugId in drugs ) {
            mw.calculators.drugs[ drugId ] = drugs[ drugId ];
        }
    };

    mw.calculators.addDrugDosages = function( drugId, drugDosageData ) {
        var drug = mw.calculators.getDrug( drugId );

        if( !drug ) {
            throw new Error( 'DrugDosage references drug "' + drugId + '" which is not defined' );
        }

        drug.addDosages( drugDosageData );
    };

    mw.calculators.getDrug = function( drugId ) {
        if( mw.calculators.drugs.hasOwnProperty( drugId ) ) {
            return mw.calculators.drugs[ drugId ];
        } else {
            return null;
        }
    };



    /**
     * Class Drug
     * @param {Object} propertyValues
     * @returns {mw.calculators.objectClasses.Drug}
     * @constructor
     */
    mw.calculators.objectClasses.Drug = function( propertyValues ) {
        mw.calculators.objectClasses.CalculatorObject.call( this, this.getProperties(), propertyValues );

        if( !this.color ) {
            this.color = mw.calculators.getOptionValue( 'defaultDrugColor' );
        }

        var color = mw.calculators.getDrugColor( this.color );

        if( !color ) {
            throw new Error( 'Invalid drug color "' + this.color + '" for drug "' + this.id + '"' );
        }

        this.color = color;

        if( this.preparations ) {
            var preparationData = this.preparations;

            this.preparations = [];

            this.addPreparations( preparationData );
        } else {
            this.preparations = [];
        }

        if( this.dosages ) {
            var dosageData = this.dosages;

            this.dosages = [];

            this.addDosages( dosageData );
        } else {
            this.dosages = [];
        }

        this.references = this.references ? mw.calculators.prepareReferences( this.references ) : [];
        this.tradeNames = this.tradeNames ? this.tradeNames : [];
    };

    mw.calculators.objectClasses.Drug.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );

    mw.calculators.objectClasses.Drug.prototype.addDosages = function( dosageData ) {
        var dosages = mw.calculators.createCalculatorObjects( 'DrugDosage', dosageData );

        for( var dosageId in dosages ) {
            dosages[ dosageId ].id = this.dosages.length;

            this.dosages.push( dosages[ dosageId ] );
        }
    };

    mw.calculators.objectClasses.Drug.prototype.addPreparations = function( preparationData ) {
        var preparations = mw.calculators.createCalculatorObjects( 'DrugPreparation', preparationData );

        for( var preparationId in preparations ) {
            preparations[ preparationId ].id = this.preparations.length;

            this.preparations.push( preparations[ preparationId ] );
        }
    };

    mw.calculators.objectClasses.Drug.prototype.getIndications = function() {
        var indications = [];

        for( var iDosage in this.dosages ) {
            if( this.dosages[ iDosage ].indication ) {
                indications.push( this.dosages[ iDosage ].indication );
            }
        }

        return indications.filter( mw.calculators.uniqueValues );
    };

    mw.calculators.objectClasses.Drug.prototype.getPopulations = function( indicationId ) {
        var populations = [];

        for( var iDosage in this.dosages ) {
            if( this.dosages[ iDosage ].population &&
                ( !indicationId || ( this.dosages[ iDosage ].indication && this.dosages[ iDosage ].indication.id === indicationId ) ) ) {
                populations.push( this.dosages[ iDosage ].population );
            }
        }

        return populations.filter( mw.calculators.uniqueValues );
    };

    mw.calculators.objectClasses.Drug.prototype.getRoutes = function( indicationId ) {
        var routes = [];

        for( var iDosage in this.dosages ) {
            if( this.dosages[ iDosage ].routes.length &&
                ( !indicationId || ( this.dosages[ iDosage ].indication && this.dosages[ iDosage ].indication.id === indicationId ) ) ) {
                for( var iRoute in this.dosages[ iDosage ].routes ) {
                    routes.push( this.dosages[ iDosage ].routes[ iRoute ] );
                }
            }
        }

        return routes.filter( mw.calculators.uniqueValues );
    };

    mw.calculators.objectClasses.Drug.prototype.getPreparations = function( excludeDilutionRequired ) {
        var preparations = this.preparations.filter( mw.calculators.uniqueValues );

        if( excludeDilutionRequired ) {
            for( var iPreparation in preparations ) {
                if( preparations[ iPreparation ].dilutionRequired ) {
                    delete preparations[ iPreparation ];
                }
            }
        }

        return preparations;
    };

    mw.calculators.objectClasses.Drug.prototype.getProperties = function() {
        return {
            required: [
                'id',
                'name'
            ],
            optional: [
                'color',
                'description',
                'dosages',
                'formula',
                'preparations',
                'references',
                'searchData',
                'tradeNames'
            ]
        };
    };





    /**
     * DrugPreparation
     */
    mw.calculators.addDrugPreparations = function( drugId, drugPreparationData ) {
        var drug = mw.calculators.getDrug( drugId );

        if( !drug ) {
            throw new Error( 'DrugPreparation references drug "' + drugId + '" which is not defined' );
        }

        drug.addPreparations( drugPreparationData );
    };



    /**
     * Class DrugPreparation
     * @param {Object} propertyValues
     * @returns {mw.calculators.objectClasses.DrugPreparation}
     * @constructor
     */
    mw.calculators.objectClasses.DrugPreparation = function( propertyValues ) {
        var properties = {
            required: [
                'id',
                'concentration'
            ],
            optional: [
                'default',
                'dilutionRequired',
                'commonDilution'
            ]
        };

        mw.calculators.objectClasses.CalculatorObject.call( this, properties, propertyValues );


        this.concentration = this.concentration.replace( 'mcg', 'ug' );

        this.concentration = math.unit( this.concentration );
    };

    mw.calculators.objectClasses.DrugPreparation.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );

    mw.calculators.objectClasses.DrugPreparation.prototype.getVolumeUnits = function() {
        // The units of concentration will always be of the form "mass / volume"
        // The regular expression matches all text leading up to the volume units
        return mw.calculators.getUnitsByBase( this.concentration ).volume;
    };

    mw.calculators.objectClasses.DrugPreparation.prototype.toString = function() {
        return mw.calculators.getValueString( this.concentration );
    };





    /**
     * Class DrugDosage
     * @param {Object} propertyValues
     * @returns {mw.calculators.objectClasses.DrugDosage}
     * @constructor
     */
    mw.calculators.objectClasses.DrugDosage = function( propertyValues ) {
        mw.calculators.objectClasses.CalculatorObject.call( this, this.getProperties(), propertyValues );

        var drugIndication = mw.calculators.getDrugIndication( this.indication );

        if( !drugIndication ) {
            throw new Error( 'Invalid indication "' + this.indication + '" for drug dosage' );
        }

        this.indication = drugIndication;

        this.population = this.population ? this.population : mw.calculators.getOptionValue( 'defaultDrugPopulation' );

        var drugPopulation = mw.calculators.getDrugPopulation( this.population );

        if( !drugPopulation ) {
            throw new Error( 'Invalid population "' + this.population + '" for drug dosage' );
        }

        this.population = drugPopulation;

        this.references = this.references ? mw.calculators.prepareReferences( this.references ) : [];

        this.routes = this.routes ? this.routes : [ mw.calculators.getOptionValue( 'defaultDrugRoute' ) ];

        if( !Array.isArray( this.routes ) ) {
            this.routes = [ this.routes ];
        }

        drugRoutes = [];

        for( var iRoute in this.routes ) {
            var drugRouteId = this.routes[ iRoute ];
            var drugRoute = mw.calculators.getDrugRoute( drugRouteId );

            if( !drugRoute ) {
                throw new Error( 'Invalid route "' + drugRouteId + '" for drug dosage' );
            }

            drugRoutes[ iRoute ] = drugRoute;
        }

        this.routes = drugRoutes;

        // Add the dose objects to the drug
        var drugDoseData = this.dose;
        this.dose = [];

        this.addDoses( drugDoseData );
    };

    mw.calculators.objectClasses.DrugDosage.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );

    mw.calculators.objectClasses.DrugDosage.prototype.addDoses = function( drugDoseData ) {
        if( !drugDoseData ) {
            return;
        } else if( !Array.isArray( drugDoseData ) ) {
            // Each dosage can have one or more associated doses. Ensure this value is an array.
            drugDoseData = [ drugDoseData ];
        }

        var doses = mw.calculators.createCalculatorObjects( 'DrugDose', drugDoseData );

        for( var doseId in doses ) {
            doses[ doseId ].id = this.dose.length;

            this.dose.push( doses[ doseId ] );
        }
    };

    mw.calculators.objectClasses.DrugDosage.prototype.getCalculationData = function() {
        var inputData = new mw.calculators.objectClasses.CalculationData();

        inputData = inputData.merge( this.population.getCalculationData() );

        for( var iDose in this.dose ) {
            inputData = inputData.merge( this.dose[ iDose ].getCalculationData() );
        }

        return inputData;
    };

    mw.calculators.objectClasses.DrugDosage.prototype.getProperties = function() {
        return {
            required: [
                'id'
            ],
            optional: [
                'description',
                'dose',
                'indication',
                'population',
                'routes',
                'references'
            ]
        };
    };

    mw.calculators.objectClasses.DrugDosage.prototype.getRouteString = function() {
        var routeString = '';

        for( var iRoute in this.routes ) {
            routeString += routeString ? '/' : '';
            routeString += this.routes[ iRoute ].abbreviation;
        }

        return routeString;
    };

    mw.calculators.objectClasses.DrugDosage.prototype.hasInfo = function() {
        return this.description;
    };





    /**
     * Class DrugDose
     * @param {Object} propertyValues
     * @returns {mw.calculators.objectClasses.DrugDose}
     * @constructor
     */
    mw.calculators.objectClasses.DrugDose = function( propertyValues ) {
        mw.calculators.objectClasses.CalculatorObject.call( this, this.getProperties(), propertyValues );

        if( this.weightCalculation ) {
            var weightCalculationIds = this.weightCalculation;

            // weightCalculation property will contain references to the actual objects, so reinitialize
            this.weightCalculation = [];

            if( !Array.isArray( weightCalculationIds ) ) {
                weightCalculationIds = [ weightCalculationIds ];
            }

            for( var iWeightCalculation in weightCalculationIds ) {
                var weightCalculationId = weightCalculationIds[ iWeightCalculation ];
                var weightCalculation = mw.calculators.getCalculation( weightCalculationId );

                if( !weightCalculation ) {
                    throw new Error( 'Drug dose references weight calculation "' + weightCalculationId + '" which is not defined' );
                }

                this.weightCalculation.push( weightCalculation );
            }
        } else {
            this.weightCalculation = [];
        }

        var mathProperties = this.getMathProperties();
        var isWeightDependent = false;

        for( var iMathProperty in mathProperties ) {
            var mathProperty = mathProperties[ iMathProperty ];

            if( this[ mathProperty ] ) {
                // TODO consider making a UnitsBase.weight.fromString()
                this[ mathProperty ] = this[ mathProperty ].replace( 'kg', 'kgwt' );
                this[ mathProperty ] = this[ mathProperty ].replace( 'mcg', 'ug' );

                this[ mathProperty ] = math.unit( this[ mathProperty ] );

                if( mw.calculators.isValueDependent( this[ mathProperty ], 'weight' ) ) {
                    isWeightDependent = true;
                }
            } else {
                this[ mathProperty ] = null;
            }
        }

        if( isWeightDependent ) {
            // Default is tbw
            this.weightCalculation.push( mw.calculators.getCalculation( 'tbw' ) );
        }
    };

    mw.calculators.objectClasses.DrugDose.prototype = Object.create( mw.calculators.objectClasses.CalculatorObject.prototype );

    mw.calculators.objectClasses.DrugDose.prototype.getAdministration = function() {
        var administration = '';

        if( this.frequency ) {
            administration += administration ? ' ' : '';
            administration += this.frequency;
        }

        if( this.duration ) {
            administration += administration ? ' ' : '';
            administration += 'over ' + this.duration;
        }

        return administration;
    };

    mw.calculators.objectClasses.DrugDose.prototype.getCalculationData = function() {
        var calculationData = new mw.calculators.objectClasses.CalculationData();

        for( var iWeightCalculation in this.weightCalculation ) {
            calculationData.calculations.optional.push( this.weightCalculation[ iWeightCalculation ].id );
        }

        return calculationData;
    };

    mw.calculators.objectClasses.DrugDose.prototype.getMathProperties = function() {
        return [
            'dose',
            'min',
            'max',
            'absoluteMin',
            'absoluteMax'
        ];
    };

    mw.calculators.objectClasses.DrugDose.prototype.getProperties = function() {
        return {
            required: [
                'id'
            ],
            optional: [
                'absoluteMax',
                'absoluteMin',
                'dose',
                'duration',
                'frequency',
                'min',
                'max',
                'name',
                'text',
                'weightCalculation'
            ]
        };
    };

}() );