text:
- Refactor Future API

## 0.0.3

- Remove dart:io dependency

## 0.0.2

- Bug Fix for brackets in urls

## 0.0.1

- Initial version, basic support for reading RSS 2.0 feeds

redpajama_set_name: RedPajamaGithub


text:
package com.cloudera.hue.livy

import java.io.{FileInputStream, InputStreamReader, File}
import java.util.Properties

import scala.annotation.tailrec
import scala.collection.JavaConversions._
import scala.concurrent.TimeoutException
import scala.concurrent.duration.Duration

object Utils {
  def getPropertiesFromFile(filename: String): Map[String, String] = {
    val file = new File(filename)
    require(file.exists(), s"Properties file $file does not exist")
    require(file.isFile, s"Properties file $file is not a normal file")

    val inReader = new InputStreamReader(new FileInputStream(file), "UTF-8")
    try {
      val properties = new Properties()
      properties.load(inReader)
      properties.stringPropertyNames().map(k => (k, properties(k).trim())).toMap
    } finally {
      inReader.close()
    }
  }

  def getDefaultPropertiesFile(env: Map[String, String] = sys.env): String = {
    env.get("LIVY_CONF_DIR")
      .orElse(env.get("LIVY_HOME").map(path => s"$path${File.separator}conf"))
      .map(path => new File(s"$path${File.separator}livy-defaults.conf"))
      .filter(_.isFile)
      .map(_.getAbsolutePath)
      .orNull
  }

  def loadDefaultLivyProperties(conf: LivyConf, filePath: String = null) = {
    val path = Option(filePath).getOrElse(getDefaultPropertiesFile())
    Option(path).foreach { path =>
      getPropertiesFromFile(path).filter { case (k, v) =>
        k.startsWith("livy.")
      }.foreach { case (k, v) =>
        conf.setIfMissing(k, v)
        sys.props.getOrElseUpdate(k, v)
      }
    }
  }

  def jarOfClass(cls: Class[_]): Option[String] = {
    val uri = cls.getResource("/" + cls.getName.replace('.', '/') + ".class")
    if (uri != null) {
      val uriStr = uri.toString
      if (uriStr.startsWith("jar:file:")) {
        Some(uriStr.substring("jar:file:".length, uriStr.indexOf("!")))
      } else {
        None
      }
    } else {
      None
    }
  }

  /**
   * Checks if event has occurred during some time period. This performs an exponential backoff
   * to limit the poll calls.
   *
   * @param checkForEvent
   * @param atMost
   * @throws java.util.concurrent.TimeoutException
   * @throws java.lang.InterruptedException
   * @return
   */
  @throws(classOf[TimeoutException])
  @throws(classOf[InterruptedException])
  final def waitUntil(checkForEvent: () => Boolean, atMost: Duration) = {
    val endTime = System.currentTimeMillis() + atMost.toMillis

    @tailrec
    def aux(count: Int): Unit = {
      if (!checkForEvent()) {
        val now = System.currentTimeMillis()

        if (now < endTime) {
          val sleepTime = Math.max(10 * (2 << (count - 1)), 1000)
          Thread.sleep(sleepTime)
          aux(count + 1)
        } else {
          throw new TimeoutException
        }
      }
    }

    aux(1)
  }

  /** Returns if the process is still running */
  def isProcessAlive(process: Process): Boolean = {
    try {
      process.exitValue()
      false
    } catch {
      case _: IllegalThreadStateException =>
        true
    }
  }

}


text:
@interface HNSortHelperTests : XCTestCase
{
    NSArray *items;
}
@end

@implementation HNSortHelperTests

- (void)setUp {
    [super setUp];

    HNItem *item3 = [[HNItem alloc] initWithIdentifier:3];
    item3.time = 3;

    HNItem *item2 = [[HNItem alloc] initWithIdentifier:2];
    item2.time = 2;

    HNItem *item1 = [[HNItem alloc] initWithIdentifier:1];
    item1.time = 1;

    items = @[item3,item2,item1];
}

- (void)tearDown {
    items = nil;
    [super tearDown];
}

- (void)testSortHelperSortsItemsToMatchIdentifierList {
    NSArray *identifiers = @[@"1",@"2",@"3"];
    NSArray *sortedItems = [HNSortHelper sortHNItems:items toMatchIdentifiers:identifiers];

    HNItem *sortedItem1 = sortedItems[0];
    HNItem *sortedItem2 = sortedItems[1];
    HNItem *sortedItem3 = sortedItems[2];

    XCTAssertTrue(sortedItem1.identifier == 1, @"Items were not sorted to match the order of the identifiers");
    XCTAssertTrue(sortedItem2.identifier == 2, @"Items were not sorted to match the order of the identifiers");
    XCTAssertTrue(sortedItem3.identifier == 3, @"Items were not sorted to match the order of the identifiers");
}

- (void)testSortHelperSortsItemsByTime {
    NSArray *sortedItems = [HNSortHelper sortHNItems:items];
    HNItem *sortedItem1 = sortedItems[0];
    HNItem *sortedItem2 = sortedItems[1];
    HNItem *sortedItem3 = sortedItems[2];

    XCTAssertTrue(sortedItem1.time == 3, @"Items were not sorted by decreasing time");
    XCTAssertTrue(sortedItem2.time == 2, @"Items were not sorted by decreasing time");
    XCTAssertTrue(sortedItem3.time == 1, @"Items were not sorted by decreasing time");
}

@end


text:
'use strict';

const express = require('express');
const app = express();
// console.log(process.env.PORT)
const port = process.env.PORT || 3000

const requestTime = (req, res, next) => {
  req.requestedTime = Date.now();
  next()
}

app.use(express.static(__dirname + '/public'))

app.use(requestTime)

app.get('/hello', (req, res, next) => {
  console.log('Hey there world')
  console.log(`ran at ${req.requestedTime}`)
  res.sendFile(__dirname + '/public/hello.html')
})

app.listen(port, () => {
 console.log('this is the port you are looking for')
})


text:
<?php

namespace PhpOffice\PhpSpreadsheet\Shared\Trend;

use PhpOffice\PhpSpreadsheet\Shared\JAMA\Matrix;

class PolynomialBestFit extends BestFit
{
    /**
     * Algorithm type to use for best-fit
     * (Name of this Trend class).
     *
     * @var string
     */
    protected $bestFitType = 'polynomial';

    /**
     * Polynomial order.
     *
     * @var int
     */
    protected $order = 0;

    /**
     * Return the order of this polynomial.
     *
     * @return int
     */
    public function getOrder()
    {
        return $this->order;
    }

    /**
     * Return the Y-Value for a specified value of X.
     *
     * @param float $xValue X-Value
     *
     * @return float Y-Value
     */
    public function getValueOfYForX($xValue)
    {
        $retVal = $this->getIntersect();
        $slope = $this->getSlope();
        // @phpstan-ignore-next-line
        foreach ($slope as $key => $value) {
            if ($value != 0.0) {
                $retVal += $value * $xValue ** ($key + 1);
            }
        }

        return $retVal;
    }

    /**
     * Return the X-Value for a specified value of Y.
     *
     * @param float $yValue Y-Value
     *
     * @return float X-Value
     */
    public function getValueOfXForY($yValue)
    {
        return ($yValue - $this->getIntersect()) / $this->getSlope();
    }

    /**
     * Return the Equation of the best-fit line.
     *
     * @param int $dp Number of places of decimal precision to display
     *
     * @return string
     */
    public function getEquation($dp = 0)
    {
        $slope = $this->getSlope($dp);
        $intersect = $this->getIntersect($dp);

        $equation = 'Y = ' . $intersect;
        // @phpstan-ignore-next-line
        foreach ($slope as $key => $value) {
            if ($value != 0.0) {
                $equation .= ' + ' . $value . ' * X';
                if ($key > 0) {
                    $equation .= '^' . ($key + 1);
                }
            }
        }

        return $equation;
    }

    /**
     * Return the Slope of the line.
     *
     * @param int $dp Number of places of decimal precision to display
     *
     * @return float
     */
    public function getSlope($dp = 0)
    {
        if ($dp != 0) {
            $coefficients = [];
            foreach ($this->slope as $coefficient) {
                $coefficients[] = round($coefficient, $dp);
            }

            // @phpstan-ignore-next-line
            return $coefficients;
        }

        return $this->slope;
    }

    public function getCoefficients($dp = 0)
    {
        return array_merge([$this->getIntersect($dp)], $this->getSlope($dp));
    }

    /**
     * Execute the regression and calculate the goodness of fit for a set of X and Y data values.
     *
     * @param int $order Order of Polynomial for this regression
     * @param float[] $yValues The set of Y-values for this regression
     * @param float[] $xValues The set of X-values for this regression
     */
    private function polynomialRegression($order, $yValues, $xValues): void
    {
        // calculate sums
        $x_sum = array_sum($xValues);
        $y_sum = array_sum($yValues);
        $xx_sum = $xy_sum = $yy_sum = 0;
        for ($i = 0; $i < $this->valueCount; ++$i) {
            $xy_sum += $xValues[$i] * $yValues[$i];
            $xx_sum += $xValues[$i] * $xValues[$i];
            $yy_sum += $yValues[$i] * $yValues[$i];
        }
        /*
         *    This routine uses logic from the PHP port of polyfit version 0.1
         *    written by Michael Bommarito and Paul Meagher
         *
         *    The function fits a polynomial function of order $order through
         *    a series of x-y data points using least squares.
         *
         */
        $A = [];
        $B = [];
        for ($i = 0; $i < $this->valueCount; ++$i) {
            for ($j = 0; $j <= $order; ++$j) {
                $A[$i][$j] = $xValues[$i] ** $j;
            }
        }
        for ($i = 0; $i < $this->valueCount; ++$i) {
            $B[$i] = [$yValues[$i]];
        }
        $matrixA = new Matrix($A);
        $matrixB = new Matrix($B);
        $C = $matrixA->solve($matrixB);

        $coefficients = [];
        for ($i = 0; $i < $C->getRowDimension(); ++$i) {
            $r = $C->get($i, 0);
            if (abs($r) <= 10 ** (-9)) {
                $r = 0;
            }
            $coefficients[] = $r;
        }

        $this->intersect = array_shift($coefficients);
        $this->slope = $coefficients;

        $this->calculateGoodnessOfFit($x_sum, $y_sum, $xx_sum, $yy_sum, $xy_sum, 0, 0, 0);
        foreach ($this->xValues as $xKey => $xValue) {
            $this->yBestFitValues[$xKey] = $this->getValueOfYForX($xValue);
        }
    }

    /**
     * Define the regression and calculate the goodness of fit for a set of X and Y data values.
     *
     * @param int $order Order of Polynomial for this regression
     * @param float[] $yValues The set of Y-values for this regression
     * @param float[] $xValues The set of X-values for this regression
     */
    public function __construct($order, $yValues, $xValues = [])
    {
        parent::__construct($yValues, $xValues);

        if (!$this->error) {
            if ($order < $this->valueCount) {
                $this->bestFitType .= '_' . $order;
                $this->order = $order;
                $this->polynomialRegression($order, $yValues, $xValues);
                if (($this->getGoodnessOfFit() < 0.0) || ($this->getGoodnessOfFit() > 1.0)) {
                    $this->error = true;
                }
            } else {
                $this->error = true;
            }
        }
    }
}


text:
'use strict'

var Handlebars = require('handlebars/runtime')
var path = require('path')
var views = require(path.join(__dirname, '/views.js'))

module.exports.build = (data, callback) => {
  Handlebars.registerPartial('researchTesting/page', Handlebars.templates['researchTesting/page'])
  Handlebars.registerPartial('style', Handlebars.templates['style'])

  Handlebars.registerPartial('layouts/base', Handlebars.templates['layouts/base'])
  Handlebars.registerPartial('researchTesting/header', Handlebars.templates['researchTesting/header'])
  Handlebars.registerPartial('researchTesting/clientandpatient-info', Handlebars.templates['researchTesting/clientandpatient-info'])
  Handlebars.registerPartial('researchTesting/consult', Handlebars.templates['researchTesting/consult'])
  Handlebars.registerPartial('oncology/hematology-menu', Handlebars.templates['oncology/hematology-menu'])
  Handlebars.registerPartial('oncology/solid-tumor-menu', Handlebars.templates['oncology/solid-tumor-menu'])

  var template = Handlebars.templates['researchTesting/page']
  var result = template(data)
  callback(null, result)
}


text:
 //  Copyright 2007-2010 Portland State University, University of Wisconsin-Madison
//  Author: Robert Scheller, Ben Sulman, Melissa Lucash

using Edu.Wisc.Forest.Flel.Util;
using Landis.Core;
using Landis.SpatialModeling;
using System.Collections.Generic;
using Landis.Library.LeafBiomassCohorts;
using System;

namespace Landis.Extension.Succession.NetEcosystemCN
{
    /// <summary>
    /// Calculations for an individual cohort's biomass.
    /// </summary>
    public class CohortBiomass
        : Landis.Library.LeafBiomassCohorts.ICalculator
    {

        /// <summary>
        /// The single instance of the biomass calculations that is used by
        /// the plug-in.
        /// </summary>
        public static CohortBiomass Calculator;

        //  Ecoregion where the cohort's site is located
        private IEcoregion ecoregion;
        public static double SpinupMortalityFraction;
        private double defoliation;
        private double defoliatedLeafBiomass;

        //---------------------------------------------------------------------

        public CohortBiomass()
        {
        }

        //---------------------------------------------------------------------

        /// <summary>
        /// Computes the change in a cohort's biomass due to Annual Net Primary
        /// Productivity (ANPP), age-related mortality (M_AGE), and development-
        /// related mortality (M_BIO).
        /// </summary>
        public float[] ComputeChange(ICohort cohort, ActiveSite site)
        {

            ecoregion = PlugIn.ModelCore.Ecoregion[site];

            // First call to the Calibrate Log:
            if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode)
                Outputs.CalibrateLog.Write("{0},{1},{2},{3},{4},{5:0.0},{6:0.0},", PlugIn.ModelCore.CurrentTime, Main.Month + 1, ecoregion.Index, cohort.Species.Name, cohort.Age, cohort.WoodBiomass, cohort.LeafBiomass);

            double siteBiomass = Main.ComputeLivingBiomass(SiteVars.Cohorts[site]);

            if(siteBiomass < 0)
                throw new ApplicationException("Error: Site biomass < 0");

            // ****** Mortality *******
            // Age-related mortality includes woody and standing leaf biomass.
            double[] mortalityAge = ComputeAgeMortality(cohort, site);

            //  Growth-related mortality
            double[] mortalityGrowth = ComputeGrowthMortality(cohort, site);

            double[] totalMortality = new double[2]{Math.Min(cohort.WoodBiomass, mortalityAge[0] + mortalityGrowth[0]), Math.Min(cohort.LeafBiomass, mortalityAge[1] + mortalityGrowth[1])};
            double nonDisturbanceLeafFall = totalMortality[1];

            // ****** Growth *******
            double[] actualANPP = ComputeActualANPP(cohort, site, siteBiomass, mortalityAge);

            double scorch = 0.0;
            defoliatedLeafBiomass = 0.0;

            if (Main.Month == 6)  //July = 6
            {
                if (SiteVars.FireSeverity != null && SiteVars.FireSeverity[site] > 0)
                    scorch = FireEffects.CrownScorching(cohort, SiteVars.FireSeverity[site]);

                if (scorch > 0.0)  // NEED TO DOUBLE CHECK WHAT CROWN SCORCHING RETURNS
                    totalMortality[1] = Math.Min(cohort.LeafBiomass, scorch + totalMortality[1]);

                // Defoliation (index) ranges from 1.0 (total) to none (0.0).
                if (PlugIn.ModelCore.CurrentTime > 0) //Skip this during initialization
                {
                    int cohortBiomass = (int)(cohort.LeafBiomass + cohort.WoodBiomass);
                    defoliation = Landis.Library.Biomass.CohortDefoliation.Compute(site, cohort.Species, cohortBiomass, (int)siteBiomass);
                }

                if (defoliation > 1.0)
                    defoliation = 1.0;

                if (defoliation > 0.0)
                {
                    defoliatedLeafBiomass = (cohort.LeafBiomass) * defoliation;
                   if (totalMortality[1] + defoliatedLeafBiomass - cohort.LeafBiomass > 0.001)
                        defoliatedLeafBiomass = cohort.LeafBiomass - totalMortality[1];
                    //PlugIn.ModelCore.UI.WriteLine("Defoliation.Month={0:0.0}, LeafBiomass={1:0.00}, DefoliatedLeafBiomass={2:0.00}, TotalLeafMort={2:0.00}", Main.Month, cohort.LeafBiomass, defoliatedLeafBiomass , mortalityAge[1]);

                    ForestFloor.AddFrassLitter(defoliatedLeafBiomass, cohort.Species, site);

                }
            }
            else
            {
                defoliation = 0.0;
                defoliatedLeafBiomass = 0.0;
            }

            // RMS 03/2016: Additional mortality as reaching capacity limit:  SAVE FOR NEXT RELEASE
            //double maxBiomass = SpeciesData.B_MAX_Spp[cohort.Species][ecoregion];
            //double limitCapacity = Math.Min(1.0, Math.Exp(siteBiomass / maxBiomass * 5.0) / Math.Exp(5.0));  // 1.0 = total limit; 0.0 = No limit
            //totalMortality[0] += (actualANPP[0] * limitCapacity); // totalMortality not to exceed ANPP allocation

            if (totalMortality[0] <= 0.0 || cohort.WoodBiomass <= 0.0)
                totalMortality[0] = 0.0;

            if (totalMortality[1] <= 0.0 || cohort.LeafBiomass <= 0.0)
                totalMortality[1] = 0.0;

            if ((totalMortality[0]) > cohort.WoodBiomass)
            {
                PlugIn.ModelCore.UI.WriteLine("Warning: WOOD Mortality exceeds cohort wood biomass. M={0:0.0}, B={1:0.0}", (totalMortality[0]), cohort.WoodBiomass);
                PlugIn.ModelCore.UI.WriteLine("Warning: If M>B, then list mortality. Mage={0:0.0}, Mgrow={1:0.0},", mortalityAge[0], mortalityGrowth[0]);
                throw new ApplicationException("Error: WOOD Mortality exceeds cohort biomass");

            }
            if ((totalMortality[1] + defoliatedLeafBiomass - cohort.LeafBiomass) > 0.01)
            {
                PlugIn.ModelCore.UI.WriteLine("Warning: LEAF Mortality exceeds cohort biomass. Mortality={0:0.000}, Leafbiomass={1:0.000}", (totalMortality[1] + defoliatedLeafBiomass), cohort.LeafBiomass);
                PlugIn.ModelCore.UI.WriteLine("Warning: If M>B, then list mortality. Mage={0:0.00}, Mgrow={1:0.00}, Mdefo={2:0.000},", mortalityAge[1], mortalityGrowth[1], defoliatedLeafBiomass);
                throw new ApplicationException("Error: LEAF Mortality exceeds cohort biomass");

            }
            float deltaWood = (float)(actualANPP[0] - totalMortality[0]);
            float deltaLeaf = (float)(actualANPP[1] - totalMortality[1] - defoliatedLeafBiomass);

            float[] deltas = new float[2] { deltaWood, deltaLeaf };

            //if((totalMortality[1] + defoliatedLeafBiomass) > cohort.LeafBiomass)
            //   PlugIn.ModelCore.UI.WriteLine("Warning: Leaf Mortality exceeds cohort leaf biomass. M={0:0.0}, B={1:0.0}, DefoLeafBiomass={2:0.0}, defoliationIndex={3:0.0}", totalMortality[1], cohort.LeafBiomass, defoliatedLeafBiomass, defoliation);

            UpdateDeadBiomass(cohort, site, totalMortality);

            CalculateNPPcarbon(site, cohort, actualANPP);

            AvailableN.AdjustAvailableN(cohort, site, actualANPP);

            if (OtherData.CalibrateMode && PlugIn.ModelCore.CurrentTime > 0)
            {
                Outputs.CalibrateLog.WriteLine("{0:0.00},{1:0.00},{2:0.00},{3:0.00},", deltaWood, deltaLeaf, totalMortality[0], totalMortality[1]);
                //Outputs.CalibrateLog.WriteLine("{0:0.00}, {1:0.00}, {2:0.00}", resorbedNused, mineralNused, totalNdemand);
            }

            return deltas;
        }

        //---------------------------------------------------------------------

        private double[] ComputeActualANPP(ICohort    cohort,
                                         ActiveSite site,
                                         double    siteBiomass,
                                         double[]   mortalityAge)
        {

            double leafFractionNPP  = FunctionalType.Table[SpeciesData.FuncType[cohort.Species]].FCFRACleaf;
            double maxBiomass       = SpeciesData.B_MAX_Spp[cohort.Species][ecoregion];
            double sitelai          = SiteVars.LAI[site];
            double maxNPP           = SpeciesData.ANPP_MAX_Spp[cohort.Species][ecoregion];

            double limitT   = calculateTemp_Limit(site, cohort.Species);

            double limitH20 = calculateWater_Limit(site, ecoregion, cohort.Species);

            double limitLAI = calculateLAI_Limit(((double) cohort.LeafBiomass * 0.47), ((double) cohort.WoodBiomass * 0.47), cohort.Species);

            // RMS 03/2016: Testing alternative more similar to how Biomass Succession operates: REMOVE FOR NEXT RELEASE
            double limitCapacity = 1.0 - Math.Min(1.0, Math.Exp(siteBiomass / maxBiomass * 5.0) / Math.Exp(5.0));

            //double potentialNPP = maxNPP * limitLAI * limitH20 * limitT; // * limitCapacity;
            double potentialNPP = maxNPP * limitLAI * limitH20 * limitT * limitCapacity;

            double limitN = calculateN_Limit(site, cohort, potentialNPP, leafFractionNPP);

            potentialNPP *= limitN;

            //if (Double.IsNaN(limitT) || Double.IsNaN(limitH20) || Double.IsNaN(limitLAI) || Double.IsNaN(limitCapacity) || Double.IsNaN(limitN))
            //{
            //    PlugIn.ModelCore.UI.WriteLine("  A limit = NaN!  Will set to zero.");
            //    PlugIn.ModelCore.UI.WriteLine("  Yr={0},Mo={1}.     GROWTH LIMITS: LAI={2:0.00}, H20={3:0.00}, N={4:0.00}, T={5:0.00}, Capacity={6:0.0}", PlugIn.ModelCore.CurrentTime, month + 1, limitLAI, limitH20, limitN, limitT, limitCapacity);
            //    PlugIn.ModelCore.UI.WriteLine("  Yr={0},Mo={1}.     Other Information: MaxB={2}, Bsite={3}, Bcohort={4:0.0}, SoilT={5:0.0}.", PlugIn.ModelCore.CurrentTime, month + 1, maxBiomass, (int)siteBiomass, (cohort.WoodBiomass + cohort.LeafBiomass), SiteVars.SoilTemperature[site]);
            //}

            //  Age mortality is discounted from ANPP to prevent the over-
            //  estimation of growth.  ANPP cannot be negative.
            double actualANPP = Math.Max(0.0, potentialNPP - mortalityAge[0] - mortalityAge[1]);

            // Growth can be reduced by another extension via this method.
            // To date, no extension has been written to utilize this hook.
            double growthReduction = CohortGrowthReduction.Compute(cohort, site);

            if (growthReduction > 0.0)
            {
                actualANPP *= (1.0 - growthReduction);
            }

            double leafNPP  = actualANPP * leafFractionNPP;
            double woodNPP  = actualANPP * (1.0 - leafFractionNPP);

            if (Double.IsNaN(leafNPP) || Double.IsNaN(woodNPP))

            {
                PlugIn.ModelCore.UI.WriteLine("  EITHER WOOD or LEAF NPP = NaN!  Will set to zero.");
                //PlugIn.ModelCore.UI.WriteLine("  Yr={0},Mo={1}, SpeciesName={2}, CohortAge={3}.   GROWTH LIMITS: LAI={4:0.00}, H20={5:0.00}, N={6:0.00}, T={7:0.00}, Capacity={8:0.0}.", PlugIn.ModelCore.CurrentTime, Main.Month + 1, cohort.Species.Name, cohort.Age, limitLAI, limitH20, limitN, limitT, limitCapacity);
                PlugIn.ModelCore.UI.WriteLine("  Yr={0},Mo={1}.     Other Information: MaxB={2}, Bsite={3}, Bcohort={4:0.0}, SoilT={5:0.0}.", PlugIn.ModelCore.CurrentTime, Main.Month + 1, maxBiomass, (int)siteBiomass, (cohort.WoodBiomass + cohort.LeafBiomass), SiteVars.SoilTemperature[site]);
                PlugIn.ModelCore.UI.WriteLine("  Yr={0},Mo={1}.     WoodNPP={2:0.00}, LeafNPP={3:0.00}.", PlugIn.ModelCore.CurrentTime, Main.Month + 1, woodNPP, leafNPP);
                if (Double.IsNaN(leafNPP))
                    leafNPP = 0.0;
                if (Double.IsNaN(woodNPP))
                    woodNPP = 0.0;

            }

            if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode)
            {
                //Outputs.CalibrateLog.Write("{0:0.00},{1:0.00},{2:0.00},{3:0.00}, {4:0.00},", limitLAI, limitH20, limitT, limitCapacity, limitN);
                Outputs.CalibrateLog.Write("{0:0.00},{1:0.00},{2:0.00},{3:0.00},", limitLAI, limitH20, limitT, limitN);
                Outputs.CalibrateLog.Write("{0},{1},{2},{3:0.0},{4:0.0},", maxNPP, maxBiomass, (int)siteBiomass, (cohort.WoodBiomass + cohort.LeafBiomass), SiteVars.SoilTemperature[site]);
                Outputs.CalibrateLog.Write("{0:0.00},{1:0.00},", woodNPP, leafNPP);
            }

            return new double[2]{woodNPP, leafNPP};

        }

        //---------------------------------------------------------------------

        /// <summary>
        /// Computes M_AGE_ij: the mortality caused by the aging of the cohort.
        /// See equation 6 in Scheller and Mladenoff, 2004.
        /// </summary>
        private double[] ComputeAgeMortality(ICohort cohort, ActiveSite site)
        {

            double monthAdjust = 1.0 / 12.0;
            double totalBiomass = (double) (cohort.WoodBiomass + cohort.LeafBiomass);
            double max_age      = (double) cohort.Species.Longevity;
            double d            = FunctionalType.Table[SpeciesData.FuncType[cohort.Species]].MortCurveShape;

            double M_AGE_wood =    cohort.WoodBiomass *  monthAdjust *
                                    Math.Exp((double) cohort.Age / max_age * d) / Math.Exp(d);

            double M_AGE_leaf =    cohort.LeafBiomass *  monthAdjust *
                                    Math.Exp((double) cohort.Age / max_age * d) / Math.Exp(d);

            if (PlugIn.ModelCore.CurrentTime <= 0 &&  SpinupMortalityFraction > 0.0)
            {
                M_AGE_wood += cohort.Biomass * SpinupMortalityFraction;
                M_AGE_leaf += cohort.Biomass * SpinupMortalityFraction;
            }

            M_AGE_wood = Math.Min(M_AGE_wood, cohort.WoodBiomass);
            M_AGE_leaf = Math.Min(M_AGE_leaf, cohort.LeafBiomass);

            double[] M_AGE = new double[2]{M_AGE_wood, M_AGE_leaf};

            SiteVars.WoodMortality[site] += (M_AGE_wood);

            if(M_AGE_wood < 0.0 || M_AGE_leaf < 0.0)
            {
                PlugIn.ModelCore.UI.WriteLine("Mwood={0}, Mleaf={1}.", M_AGE_wood, M_AGE_leaf);
                throw new ApplicationException("Error: Woody or Leaf Age Mortality is < 0");
            }

            if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode)
                Outputs.CalibrateLog.Write("{0:0.00},{1:0.00},", M_AGE_wood, M_AGE_leaf);

            return M_AGE;
        }
        //---------------------------------------------------------------------

        /// <summary>
        /// Monthly mortality as a function of standing leaf and wood biomass.
        /// </summary>
        private double[] ComputeGrowthMortality(ICohort cohort, ActiveSite site)
        {
            //if(cohort.WoodBiomass <= 0 || cohort.LeafBiomass <= 0)
            //    return (new double[2]{0.0, 0.0});

            double M_wood = cohort.WoodBiomass * FunctionalType.Table[SpeciesData.FuncType[cohort.Species]].MonthlyWoodMortality;
            double M_leaf = 0.0;

            // Leaves and Needles dropped.
            if(SpeciesData.LeafLongevity[cohort.Species] > 1.0)
            {
                M_leaf = cohort.LeafBiomass / (double) SpeciesData.LeafLongevity[cohort.Species] / 12.0;  //Needle deposit spread across the year.

            }
            else
            {
                if(Main.Month +1 == FunctionalType.Table[SpeciesData.FuncType[cohort.Species]].LeafNeedleDrop)
                {
                    M_leaf = cohort.LeafBiomass / 2.0;  //spread across 2 months

                }
                if (Main.Month +2 > FunctionalType.Table[SpeciesData.FuncType[cohort.Species]].LeafNeedleDrop)
                {
                    M_leaf = cohort.LeafBiomass;  //drop the remainder
                }
            }

            double[] M_BIO = new double[2]{M_wood, M_leaf};

            if(M_wood < 0.0 || M_leaf < 0.0)
            {
                PlugIn.ModelCore.UI.WriteLine("Mwood={0}, Mleaf={1}.", M_wood, M_leaf);
                throw new ApplicationException("Error: Wood or Leaf Growth Mortality is < 0");
            }

            if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode)
                Outputs.CalibrateLog.Write("{0:0.00},{1:0.00},", M_wood, M_leaf);

            SiteVars.WoodMortality[site] += (M_wood);

            return M_BIO;

        }

        //---------------------------------------------------------------------

        private void UpdateDeadBiomass(ICohort cohort, ActiveSite site, double[] totalMortality)
        {

            double mortality_wood    = (double) totalMortality[0];
            double mortality_nonwood = (double)totalMortality[1];

            //  Add mortality to dead biomass pools.
            //  Coarse root mortality is assumed proportional to aboveground woody mortality
            //    mass is assumed 25% of aboveground wood (White et al. 2000, Niklas & Enquist 2002)
            if(mortality_wood > 0.0)
            {
                ForestFloor.AddWoodLitter(mortality_wood, cohort.Species, site);
                Roots.AddCoarseRootLitter(mortality_wood, cohort, cohort.Species, site);
            }

            if(mortality_nonwood > 0.0)
            {
                AvailableN.AddResorbedN(cohort, totalMortality[1], site); //ignoring input from scorching, which is rare, but not resorbed.
                ForestFloor.AddResorbedFoliageLitter(mortality_nonwood, cohort.Species, site);
                Roots.AddFineRootLitter(mortality_nonwood, cohort, cohort.Species, site);
            }

            return;

        }

        //---------------------------------------------------------------------

        /// <summary>
        /// Computes the initial biomass for a cohort at a site.
        /// </summary>
        public static float[] InitialBiomass(ISpecies species, ISiteCohorts siteCohorts,
                                            ActiveSite  site)
        {
            IEcoregion ecoregion = PlugIn.ModelCore.Ecoregion[site];

            double leafFrac = FunctionalType.Table[SpeciesData.FuncType[species]].FCFRACleaf;

            double B_ACT = SiteVars.ActualSiteBiomass(site);
            double B_MAX = SpeciesData.B_MAX_Spp[species][ecoregion];

            //  Initial biomass exponentially declines in response to
            //  competition.
            double initialBiomass = 0.002 * B_MAX * Math.Exp(-1.6 * B_ACT / B_MAX);

            initialBiomass = Math.Max(initialBiomass, 5.0);

            double initialLeafB = initialBiomass * leafFrac;
            double initialWoodB = initialBiomass - initialLeafB;
            double[] initialB = new double[2]{initialWoodB, initialLeafB};

            float[] initialWoodLeafBiomass = new float[2]{(float) initialB[0], (float) initialB[1]};

            return initialWoodLeafBiomass;
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Summarize NPP
        /// </summary>
        private static void CalculateNPPcarbon(ActiveSite site, ICohort cohort, double[] AGNPP)
        {
            double NPPwood = (double) AGNPP[0] * 0.47;
            double NPPleaf = (double) AGNPP[1] * 0.47;

            double NPPcoarseRoot = Roots.CalculateCoarseRoot(cohort, NPPwood);
            double NPPfineRoot = Roots.CalculateFineRoot(cohort, NPPleaf);

            if (Double.IsNaN(NPPwood) || Double.IsNaN(NPPleaf) || Double.IsNaN(NPPcoarseRoot) || Double.IsNaN(NPPfineRoot))
            {
                PlugIn.ModelCore.UI.WriteLine("  EITHER WOOD or LEAF NPP or COARSE ROOT or FINE ROOT = NaN!  Will set to zero.");
                PlugIn.ModelCore.UI.WriteLine("  Yr={0},Mo={1}.     WoodNPP={0}, LeafNPP={1}, CRootNPP={2}, FRootNPP={3}.", NPPwood, NPPleaf, NPPcoarseRoot, NPPfineRoot);
                if (Double.IsNaN(NPPleaf))
                    NPPleaf = 0.0;
                if (Double.IsNaN(NPPwood))
                    NPPwood = 0.0;
                if (Double.IsNaN(NPPcoarseRoot))
                    NPPcoarseRoot = 0.0;
                if (Double.IsNaN(NPPfineRoot))
                    NPPfineRoot = 0.0;
            }

            SiteVars.AGNPPcarbon[site] += NPPwood + NPPleaf;
            SiteVars.BGNPPcarbon[site] += NPPcoarseRoot + NPPfineRoot;
            SiteVars.MonthlyAGNPPcarbon[site][Main.Month] += NPPwood + NPPleaf;
            SiteVars.MonthlyBGNPPcarbon[site][Main.Month] += NPPcoarseRoot + NPPfineRoot;

            if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode)
            {
                Outputs.CalibrateLog.Write("{0:0.00},{1:0.00},", NPPwood, NPPleaf);

            }

        }

        //--------------------------------------------------------------------------
        //N limit is actual demand divided by maximum uptake.
        private double calculateN_Limit(ActiveSite site, ICohort cohort, double NPP, double leafFractionNPP)
        {

            //Get Cohort Mineral and Resorbed N allocation.
            double mineralNallocation = AvailableN.GetMineralNallocation(cohort);
            double resorbedNallocation = AvailableN.GetResorbedNallocation(cohort, site);

            //double LeafNPP = Math.Max(NPP * leafFractionNPP, 0.002 * cohort.WoodBiomass);  This allowed for Ndemand in winter when there was no leaf NPP
            double LeafNPP = (NPP * leafFractionNPP);

            double WoodNPP = NPP * (1.0 - leafFractionNPP);

            double limitN = 0.0;
            if (SpeciesData.NFixer[cohort.Species])
                limitN = 1.0;  // No limit for N-fixing shrubs
            else
            {
                // Divide allocation N by N demand here:
                //PlugIn.ModelCore.UI.WriteLine("  WoodNPP={0:0.00}, LeafNPP={1:0.00}, FineRootNPP={2:0.00}, CoarseRootNPP={3:0.00}.", WoodNPP, LeafNPP);
               double Ndemand = (AvailableN.CalculateCohortNDemand(cohort.Species, site, cohort, new double[] { WoodNPP, LeafNPP}));

                if (Ndemand > 0.0)
                {
                    limitN = Math.Min(1.0, (mineralNallocation + resorbedNallocation) / Ndemand);

                }
                else
                    limitN = 1.0; // No demand means that it is a new or very small cohort.  Will allow it to grow anyways.
            }

            if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode)
                Outputs.CalibrateLog.Write("{0:0.00},{1:0.00},", mineralNallocation, resorbedNallocation);

            return Math.Max(limitN, 0.0);
        }
        //--------------------------------------------------------------------------
        // Originally from lacalc.f of CENTURY model

        private static double calculateLAI_Limit(double leafC, double largeWoodC, ISpecies species)
        {

            //...Calculate true LAI using leaf biomass and a biomass-to-LAI
            //     conversion parameter which is the slope of a regression
            //     line derived from LAI vs Foliar Mass for Slash Pine.

            //...Calculate theoretical LAI as a function of large wood mass.
            //     There is no strong consensus on the true nature of the relationship
            //     between LAI and stemwood mass.  Version 3.0 used a negative exponential
            //     relationship between leaf mass and large wood mass, which tended to
            //     break down in very large forests.  Many sutdies have cited as "general"
            //      an increase of LAI up to a maximum, then a decrease to a plateau value
            //     (e.g. Switzer et al. 1968, Gholz and Fisher 1982).  However, this
            //     response is not general, and seems to mostly be a feature of young
            //     pine plantations.  Northern hardwoods have shown a monotonic increase
            //     to a plateau  (e.g. Switzer et al. 1968).  Pacific Northwest conifers
            //     have shown a steady increase in LAI with no plateau evident (e.g.
            //     Gholz 1982).  In this version, we use a simple saturation fucntion in
            //     which LAI increases linearly against large wood mass initially, then
            //     approaches a plateau value.  The plateau value can be set very large to
            //     give a response of steadily increasing LAI with stemwood.

            //     References:
            //             1)  Switzer, G.L., L.E. Nelson and W.H. Smith 1968.
            //                 The mineral cycle in forest stands.  'Forest
            //                 Fertilization:  Theory and Practice'.  pp 1-9
            //                 Tenn. Valley Auth., Muscle Shoals, AL.
            //
            //             2)  Gholz, H.L., and F.R. Fisher 1982.  Organic matter
            //                 production and distribution in slash pine (Pinus
            //                 elliotii) plantations.  Ecology 63(6):  1827-1839.
            //
            //             3)  Gholz, H.L.  1982.  Environmental limits on aboveground
            //                 net primary production and biomass in vegetation zones of
            //                 the Pacific Northwest.  Ecology 63:469-481.

            //...Local variables

            double lai = 0.0;
            double laitop = -0.47;  // This is the value given for all biomes in the tree.100 file.
            double btolai = FunctionalType.Table[SpeciesData.FuncType[species]].BTOLAI;
            double klai   = FunctionalType.Table[SpeciesData.FuncType[species]].KLAI;
            double maxlai = FunctionalType.Table[SpeciesData.FuncType[species]].MAXLAI;

            double rlai = (Math.Max(0.0, 1.0 - Math.Exp(btolai * leafC)));

            if (SpeciesData.LeafLongevity[species] > 1.0)
            {
                rlai = 1.0;
            }

            double tlai = maxlai * largeWoodC/(klai + largeWoodC);

            //...Choose the LAI reducer on production.  I don't really understand
            //     why we take the average in the first case, but it will probably
            //     change...

            //if (rlai < tlai) lai = (rlai + tlai) / 2.0;
            lai = tlai * rlai;
            //else lai = tlai;

            // This will allow us to set MAXLAI to zero such that LAI is completely dependent upon
            // foliar carbon, which may be necessary for simulating defoliation events.
            if(tlai <= 0.0) lai = rlai;

            //lai = tlai;  // Century 4.5 ignores rlai.

            // Limit aboveground wood production by leaf area
            //  index.
            //
            //       REF:    Efficiency of Tree Crowns and Stemwood
            //               Production at Different Canopy Leaf Densities
            //               by Waring, Newman, and Bell
            //               Forestry, Vol. 54, No. 2, 1981

            //totalLAI += lai;
            // if (totalLAI > EcoregionData.MaxLAI)
            // lai = 0.1;

            // The minimum LAI to calculate effect is 0.2.
            //if (lai < 0.5) lai = 0.5;
            if (lai < 0.1) lai = 0.1;

            //SiteVars.LAI[site] += lai; Tracking LAI.

            double LAI_limit = Math.Max(0.0, 1.0 - Math.Exp(laitop * lai));

            //This allows LAI to go to zero for deciduous trees.

            if (SpeciesData.LeafLongevity[species] <= 1.0 &&
                (Main.Month > FunctionalType.Table[SpeciesData.FuncType[species]].LeafNeedleDrop || Main.Month < 3))
            {
                lai = 0.0;
                LAI_limit = 0.0;
            }

            if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode)
                Outputs.CalibrateLog.Write("{0:0.00},{1:0.00},{2:0.00},", lai, tlai, rlai);

            //PlugIn.ModelCore.UI.WriteLine("Yr={0},Mo={1}. Spp={2}, leafC={3:0.0}, woodC={4:0.00}.", PlugIn.ModelCore.CurrentTime, month + 1, species.Name, leafC, largeWoodC);
            //PlugIn.ModelCore.UI.WriteLine("Yr={0},Mo={1}. Spp={2}, lai={3:0.0}, woodC={4:0.00}.", PlugIn.ModelCore.CurrentTime, month + 1, species.Name, lai, largeWoodC);
            //PlugIn.ModelCore.UI.WriteLine("Yr={0},Mo={1}.     LAI Limits:  lai={2:0.0}, woodLAI={3:0.0}, leafLAI={4:0.0}, LAIlimit={5:0.00}.", PlugIn.ModelCore.CurrentTime, month + 1, lai, woodLAI, leafLAI, LAI_limit);

            return LAI_limit;

        }

        //---------------------------------------------------------------------------
        //... Originally from pprdwc(wc,x,pprpts) of CENTURY

        //...This funtion returns a value for potential plant production
        //     due to water content.  Basically you have an equation of a
        //     line with a moveable y-intercept depending on the soil type.
        //     The value passed in for x is ((avh2o(1) + prcurr(month) + irract)/pet)

        //     pprpts(1):  The minimum ratio of available water to pet which
        //                 would completely limit production assuming wc=0.
        //     pprpts(2):  The effect of wc on the intercept, allows the
        //                 user to increase the value of the intercept and
        //                 thereby increase the slope of the line.
        //     pprpts(3):  The lowest ratio of available water to pet at which
        //                 there is no restriction on production.
        private static double calculateWater_Limit(ActiveSite site, IEcoregion ecoregion, ISpecies species)
        {

            // Ratio_AvailWaterToPET used to be pptprd and WaterLimit used to be pprdwc
            double Ratio_AvailWaterToPET = 0.0;
            double waterContent = EcoregionData.FieldCapacity[ecoregion] - EcoregionData.WiltingPoint[ecoregion];  // Difference between two fractions (FC - WP), not the actual water content, per se.
            double tmin = EcoregionData.AnnualWeather[ecoregion].MonthlyMinTemp[Main.Month];

            double H2Oinputs = EcoregionData.AnnualWeather[ecoregion].MonthlyPrecip[Main.Month]; //rain + irract;

            double pet = EcoregionData.AnnualWeather[ecoregion].MonthlyPET[Main.Month];
            //PlugIn.ModelCore.UI.WriteLine("pet={0}, waterContent={1}, precip={2}.", pet, waterContent, H2Oinputs);

            if (pet >= 0.01)
            {   //       Trees are allowed to access the whole soil profile -rm 2/97
                //         pptprd = (avh2o(1) + tmoist) / pet
               // pptprd = (SiteVars.AvailableWater[site] + H2Oinputs) / pet;
                Ratio_AvailWaterToPET = (SiteVars.AvailableWater[site] / pet);  //Modified by ML so that we weren't double-counting precip as in above equation
                //PlugIn.ModelCore.UI.WriteLine("RatioAvailWaterToPET={0}, AvailableWater={1}.", Ratio_AvailWaterToPET, SiteVars.AvailableWater[site]);
            }
            else Ratio_AvailWaterToPET = 0.01;

            //...The equation for the y-intercept (intcpt) is A+B*WC.  A and B
            //     determine the effect of soil texture on plant production based
            //     on moisture.

            //...Old way:
            //      intcpt = 0.0 + 1.0 * wc
            //      The second point in the equation is (.8,1.0)
            //      slope = (1.0-0.0)/(.8-intcpt)
            //      pprdwc = 1.0+slope*(x-.8)

            //...New way:

            double pprpts1 = OtherData.PPRPTS1;
            double pprpts2 = FunctionalType.Table[SpeciesData.FuncType[species]].PPRPTS2;
            double pprpts3 = FunctionalType.Table[SpeciesData.FuncType[species]].PPRPTS3;

            double intcpt = pprpts1 + (pprpts2 * waterContent);
            double slope  = 1.0 / (pprpts3 - intcpt);

            double WaterLimit = 1.0 + slope * (Ratio_AvailWaterToPET - pprpts3);

            if (WaterLimit > 1.0)  WaterLimit = 1.0;
            if (WaterLimit < 0.01) WaterLimit = 0.01;

            //PlugIn.ModelCore.UI.WriteLine("Intercept={0}, Slope={1}, WaterLimit={2}.", intcpt, slope, WaterLimit);

            if (PlugIn.ModelCore.CurrentTime > 0 && OtherData.CalibrateMode)
                Outputs.CalibrateLog.Write("{0:0.00},", SiteVars.AvailableWater[site]);

            return WaterLimit;
        }

        //-----------
        private double calculateTemp_Limit(ActiveSite site, ISpecies species)
        {
            //Originally from gpdf.f of CENTURY model
            //It calculates the limitation of soil temperature on aboveground forest potential production.
            //It is a function and only called by potcrp.f and potfor.f.

            //A1 is temperature. A2~A5 are paramters from tree.100

            //...This routine is functionally equivalent to the routine of the
            //     same name, described in the publication:

            //       Some Graphs and their Functional Forms
            //       Technical Report No. 153
            //       William Parton and George Innis (1972)
            //       Natural Resource Ecology Lab.
            //       Colorado State University
            //       Fort collins, Colorado  80523
            //...Local variables

            double A1 = SiteVars.SoilTemperature[site];
            double A2 = FunctionalType.Table[SpeciesData.FuncType[species]].PPDF1;
            double A3 = FunctionalType.Table[SpeciesData.FuncType[species]].PPDF2;
            double A4 = FunctionalType.Table[SpeciesData.FuncType[species]].PPDF3;
            double A5 = FunctionalType.Table[SpeciesData.FuncType[species]].PPDF4;

            double frac = (A3-A1) / (A3-A2);
            double U1 = 0.0;
            if (frac > 0.0)
                U1 = Math.Exp(A4 / A5 * (1.0 - Math.Pow(frac, A5))) * Math.Pow(frac, A4);

            //PlugIn.ModelCore.UI.WriteLine("  TEMPERATURE Limits:  Month={0}, Soil Temp={1:0.00}, Temp Limit={2:0.00}. [PPDF1={3:0.0},PPDF2={4:0.0},PPDF3={5:0.0},PPDF4={6:0.0}]", month+1, A1, U1,A2,A3,A4,A5);

            return U1;
        }

    }
}


text:
using NUnit.Framework;
using Particle;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace ParticleSDKTests.NUnit
{
	[TestFixture]
	public class RHTests
	{
		private String GetString(String str)
		{
			var assm = typeof(ParticleCloud).GetTypeInfo().Assembly;
			var rh = assm.GetTypes().FirstOrDefault(i => i.Name == "RH");
			if(rh == null)
			{
				Assert.Fail("Unable to locate RH class");
			}

			var c = rh.GetProperties().FirstOrDefault(i => i.Name == "C");
			if(c == null)
			{
				Assert.Fail("Unable to locate c class");
			}

			var curr = c.GetValue(null);

			var m = rh.GetMethods().FirstOrDefault(i => i.Name == "GetString");
			if(m == null)
			{
				Assert.Fail("Unable to locate GetString method on class");
			}

			var ret = m.Invoke(curr, new String[] { str });
			Assert.IsInstanceOf(typeof(String), ret);
			return (String)ret;
		}
		[Test]
		public void GetStringTest()
		{
			var v = GetString("UnitTestString");
			Assert.AreEqual("This string is just for unit testing the ResourceHelper", v);
		}
	}
}


text:
#include "third_party/blink/renderer/modules/indexeddb/idb_request.h"

#include <atomic>
#include <memory>
#include <utility>

#include "third_party/blink/public/platform/web_blob_info.h"
#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
#include "third_party/blink/renderer/bindings/modules/v8/idb_object_store_or_idb_index_or_idb_cursor.h"
#include "third_party/blink/renderer/bindings/modules/v8/to_v8_for_modules.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/core/dom/events/event_queue.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/indexed_db_names.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_cursor_with_value.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_database.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_event_dispatcher.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_request_queue_item.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_tracing.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_value.h"
#include "third_party/blink/renderer/modules/indexeddb/idb_value_wrapping.h"
#include "third_party/blink/renderer/modules/indexeddb/web_idb_callbacks_impl.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"

namespace blink {

IDBRequest::AsyncTraceState::AsyncTraceState(const char* trace_event_name)
    : trace_event_name_(nullptr) {
  // If PopulateForNewEvent is called, it sets trace_event_name_ to
  // trace_event_name. Otherwise, trace_event_name_ is nullptr, so this instance
  // is considered empty. This roundabout initialization lets us avoid calling
  // TRACE_EVENT_NESTABLE_ASYNC_END0 with an uninitalized ID.
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
      "IndexedDB", trace_event_name,
      TRACE_ID_LOCAL(PopulateForNewEvent(trace_event_name)));
}

void IDBRequest::AsyncTraceState::RecordAndReset() {
  if (trace_event_name_) {
    TRACE_EVENT_NESTABLE_ASYNC_END0("IndexedDB", trace_event_name_,
                                    TRACE_ID_LOCAL(id_));
    trace_event_name_ = nullptr;
  }
}

IDBRequest::AsyncTraceState::~AsyncTraceState() {
  if (trace_event_name_) {
    TRACE_EVENT_NESTABLE_ASYNC_END0("IndexedDB", trace_event_name_,
                                    TRACE_ID_LOCAL(id_));
  }
}

size_t IDBRequest::AsyncTraceState::PopulateForNewEvent(
    const char* trace_event_name) {
  DCHECK(trace_event_name);
  DCHECK(!trace_event_name_);
  trace_event_name_ = trace_event_name;

  static std::atomic<size_t> counter(0);
  id_ = counter.fetch_add(1, std::memory_order_relaxed);
  return id_;
}

IDBRequest* IDBRequest::Create(ScriptState* script_state,
                               IDBIndex* source,
                               IDBTransaction* transaction,
                               IDBRequest::AsyncTraceState metrics) {
  return IDBRequest::Create(script_state, Source::FromIDBIndex(source),
                            transaction, std::move(metrics));
}

IDBRequest* IDBRequest::Create(ScriptState* script_state,
                               IDBObjectStore* source,
                               IDBTransaction* transaction,
                               IDBRequest::AsyncTraceState metrics) {
  return IDBRequest::Create(script_state, Source::FromIDBObjectStore(source),
                            transaction, std::move(metrics));
}

IDBRequest* IDBRequest::Create(ScriptState* script_state,
                               IDBCursor* source,
                               IDBTransaction* transaction,
                               IDBRequest::AsyncTraceState metrics) {
  return IDBRequest::Create(script_state, Source::FromIDBCursor(source),
                            transaction, std::move(metrics));
}

IDBRequest* IDBRequest::Create(ScriptState* script_state,
                               const Source& source,
                               IDBTransaction* transaction,
                               IDBRequest::AsyncTraceState metrics) {
  IDBRequest* request = MakeGarbageCollected<IDBRequest>(
      script_state, source, transaction, std::move(metrics));
  // Requests associated with IDBFactory (open/deleteDatabase/getDatabaseNames)
  // do not have an associated transaction.
  if (transaction)
    transaction->RegisterRequest(request);
  return request;
}

IDBRequest::IDBRequest(ScriptState* script_state,
                       const Source& source,
                       IDBTransaction* transaction,
                       AsyncTraceState metrics)
    : ExecutionContextLifecycleObserver(ExecutionContext::From(script_state)),
      transaction_(transaction),
      isolate_(script_state->GetIsolate()),
      metrics_(std::move(metrics)),
      source_(source),
      event_queue_(
          MakeGarbageCollected<EventQueue>(ExecutionContext::From(script_state),
                                           TaskType::kDatabaseAccess)) {}

IDBRequest::~IDBRequest() {
  DCHECK((ready_state_ == DONE && metrics_.IsEmpty()) ||
         ready_state_ == kEarlyDeath || !GetExecutionContext());
}

void IDBRequest::Trace(Visitor* visitor) {
  visitor->Trace(transaction_);
  visitor->Trace(source_);
  visitor->Trace(result_);
  visitor->Trace(error_);
  visitor->Trace(event_queue_);
  visitor->Trace(pending_cursor_);
  EventTargetWithInlineData::Trace(visitor);
  ExecutionContextLifecycleObserver::Trace(visitor);
}

ScriptValue IDBRequest::result(ScriptState* script_state,
                               ExceptionState& exception_state) {
  if (ready_state_ != DONE) {
    // Must throw if returning an empty value. Message is arbitrary since it
    // will never be seen.
    exception_state.ThrowDOMException(
        DOMExceptionCode::kInvalidStateError,
        IDBDatabase::kRequestNotFinishedErrorMessage);
    return ScriptValue();
  }
  if (!GetExecutionContext()) {
    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                      IDBDatabase::kDatabaseClosedErrorMessage);
    return ScriptValue();
  }
  result_dirty_ = false;
  ScriptValue value = ScriptValue::From(script_state, result_);
  return value;
}

DOMException* IDBRequest::error(ExceptionState& exception_state) const {
  if (ready_state_ != DONE) {
    exception_state.ThrowDOMException(
        DOMExceptionCode::kInvalidStateError,
        IDBDatabase::kRequestNotFinishedErrorMessage);
    return nullptr;
  }
  return error_;
}

void IDBRequest::source(ScriptState* script_state,
                        IDBObjectStoreOrIDBIndexOrIDBCursor& source) const {
  if (!GetExecutionContext()) {
    source = Source();
  }
  source = source_;
}

const String& IDBRequest::readyState() const {
  DCHECK(ready_state_ == PENDING || ready_state_ == DONE);

  if (ready_state_ == PENDING)
    return indexed_db_names::kPending;

  return indexed_db_names::kDone;
}

std::unique_ptr<WebIDBCallbacks> IDBRequest::CreateWebCallbacks() {
  DCHECK(!web_callbacks_);
  auto callbacks = std::make_unique<WebIDBCallbacksImpl>(this);
  web_callbacks_ = callbacks.get();
  return callbacks;
}

void IDBRequest::Abort() {
  DCHECK(!request_aborted_);
  if (queue_item_) {
    queue_item_->CancelLoading();

    // A transaction's requests are aborted in order, so each aborted request
    // should immediately get out of the result queue.
    DCHECK(!queue_item_);
  }

  if (!GetExecutionContext())
    return;
  DCHECK(ready_state_ == PENDING || ready_state_ == DONE);
  if (ready_state_ == DONE)
    return;

  event_queue_->CancelAllEvents();

  error_.Clear();
  result_.Clear();
  EnqueueResponse(MakeGarbageCollected<DOMException>(
      DOMExceptionCode::kAbortError,
      "The transaction was aborted, so the request cannot be fulfilled."));
  request_aborted_ = true;
}

void IDBRequest::SetCursorDetails(indexed_db::CursorType cursor_type,
                                  mojom::IDBCursorDirection direction) {
  DCHECK_EQ(ready_state_, PENDING);
  DCHECK(!pending_cursor_);
  cursor_type_ = cursor_type;
  cursor_direction_ = direction;
}

void IDBRequest::SetPendingCursor(IDBCursor* cursor) {
  DCHECK_EQ(ready_state_, DONE);
  DCHECK(GetExecutionContext());
  DCHECK(transaction_);
  DCHECK(!pending_cursor_);
  DCHECK_EQ(cursor, GetResultCursor());

  has_pending_activity_ = true;
  pending_cursor_ = cursor;
  SetResult(nullptr);
  ready_state_ = PENDING;
  error_.Clear();
  transaction_->RegisterRequest(this);
}

IDBCursor* IDBRequest::GetResultCursor() const {
  if (!result_)
    return nullptr;
  if (result_->GetType() == IDBAny::kIDBCursorType)
    return result_->IdbCursor();
  if (result_->GetType() == IDBAny::kIDBCursorWithValueType)
    return result_->IdbCursorWithValue();
  return nullptr;
}

void IDBRequest::SetResultCursor(IDBCursor* cursor,
                                 std::unique_ptr<IDBKey> key,
                                 std::unique_ptr<IDBKey> primary_key,
                                 std::unique_ptr<IDBValue> value) {
  DCHECK_EQ(ready_state_, PENDING);
  cursor_key_ = std::move(key);
  cursor_primary_key_ = std::move(primary_key);
  cursor_value_ = std::move(value);

  EnqueueResultInternal(MakeGarbageCollected<IDBAny>(cursor));
}

bool IDBRequest::ShouldEnqueueEvent() const {
  const ExecutionContext* execution_context = GetExecutionContext();

  // https://crbug.com/733642 - Document::Shutdown() calls
  // LocalDOMWindow::ClearEventQueue(), which nulls out the context's event
  // queue, before calling ExecutionContext::NotifyContextDestroyed(). The
  // latter eventually calls IDBRequest::ContextDestroyed(), which aborts the
  // request. As an aborted IDBRequest is removed from its' IDBTransaction
  // result queue, it may unblock another request whose result is already
  // available. If the unblocked request hasn't received a
  // NotifyContextDestroyed() call yet, it will hang onto an ExecutionContext
  // whose event queue has been nulled out. The event queue null check covers
  // these specific circumstances.
  if (!execution_context)
    return false;

  DCHECK(ready_state_ == PENDING || ready_state_ == DONE);
  if (request_aborted_)
    return false;
  DCHECK_EQ(ready_state_, PENDING);
  DCHECK(!error_ && !result_);
  return true;
}

void IDBRequest::HandleResponse(DOMException* error) {
  transit_blob_handles_.clear();
  if (!transaction_ || !transaction_->HasQueuedResults())
    return EnqueueResponse(error);
  transaction_->EnqueueResult(std::make_unique<IDBRequestQueueItem>(
      this, error,
      WTF::Bind(&IDBTransaction::OnResultReady,
                WrapPersistent(transaction_.Get()))));
}

void IDBRequest::HandleResponse(std::unique_ptr<IDBKey> key) {
  transit_blob_handles_.clear();
  DCHECK(transaction_);
  if (!transaction_->HasQueuedResults())
    return EnqueueResponse(std::move(key));
  transaction_->EnqueueResult(std::make_unique<IDBRequestQueueItem>(
      this, std::move(key),
      WTF::Bind(&IDBTransaction::OnResultReady,
                WrapPersistent(transaction_.Get()))));
}

void IDBRequest::HandleResponse(int64_t value_or_old_version) {
  DCHECK(transit_blob_handles_.IsEmpty());
  if (!transaction_ || !transaction_->HasQueuedResults())
    return EnqueueResponse(value_or_old_version);
  transaction_->EnqueueResult(std::make_unique<IDBRequestQueueItem>(
      this, value_or_old_version,
      WTF::Bind(&IDBTransaction::OnResultReady,
                WrapPersistent(transaction_.Get()))));
}

void IDBRequest::HandleResponse() {
  DCHECK(transit_blob_handles_.IsEmpty());
  if (!transaction_ || !transaction_->HasQueuedResults())
    return EnqueueResponse();
  transaction_->EnqueueResult(std::make_unique<IDBRequestQueueItem>(
      this, WTF::Bind(&IDBTransaction::OnResultReady,
                      WrapPersistent(transaction_.Get()))));
}

void IDBRequest::HandleResponse(std::unique_ptr<WebIDBCursor> backend,
                                std::unique_ptr<IDBKey> key,
                                std::unique_ptr<IDBKey> primary_key,
                                std::unique_ptr<IDBValue> value) {
  DCHECK(transit_blob_handles_.IsEmpty());
  DCHECK(transaction_);
  bool is_wrapped = IDBValueUnwrapper::IsWrapped(value.get());
  if (!transaction_->HasQueuedResults() && !is_wrapped) {
    return EnqueueResponse(std::move(backend), std::move(key),
                           std::move(primary_key), std::move(value));
  }
  transaction_->EnqueueResult(std::make_unique<IDBRequestQueueItem>(
      this, std::move(backend), std::move(key), std::move(primary_key),
      std::move(value), is_wrapped,
      WTF::Bind(&IDBTransaction::OnResultReady,
                WrapPersistent(transaction_.Get()))));
}

void IDBRequest::HandleResponse(std::unique_ptr<IDBValue> value) {
  DCHECK(transit_blob_handles_.IsEmpty());
  DCHECK(transaction_);
  bool is_wrapped = IDBValueUnwrapper::IsWrapped(value.get());
  if (!transaction_->HasQueuedResults() && !is_wrapped)
    return EnqueueResponse(std::move(value));
  transaction_->EnqueueResult(std::make_unique<IDBRequestQueueItem>(
      this, std::move(value), is_wrapped,
      WTF::Bind(&IDBTransaction::OnResultReady,
                WrapPersistent(transaction_.Get()))));
}

void IDBRequest::HandleResponse(Vector<std::unique_ptr<IDBValue>> values) {
  DCHECK(transit_blob_handles_.IsEmpty());
  DCHECK(transaction_);
  bool is_wrapped = IDBValueUnwrapper::IsWrapped(values);
  if (!transaction_->HasQueuedResults() && !is_wrapped)
    return EnqueueResponse(std::move(values));
  transaction_->EnqueueResult(std::make_unique<IDBRequestQueueItem>(
      this, std::move(values), is_wrapped,
      WTF::Bind(&IDBTransaction::OnResultReady,
                WrapPersistent(transaction_.Get()))));
}

void IDBRequest::HandleResponse(std::unique_ptr<IDBKey> key,
                                std::unique_ptr<IDBKey> primary_key,
                                std::unique_ptr<IDBValue> value) {
  DCHECK(transit_blob_handles_.IsEmpty());
  DCHECK(transaction_);
  bool is_wrapped = IDBValueUnwrapper::IsWrapped(value.get());
  if (!transaction_->HasQueuedResults() && !is_wrapped) {
    return EnqueueResponse(std::move(key), std::move(primary_key),
                           std::move(value));
  }

  transaction_->EnqueueResult(std::make_unique<IDBRequestQueueItem>(
      this, std::move(key), std::move(primary_key), std::move(value),
      is_wrapped,
      WTF::Bind(&IDBTransaction::OnResultReady,
                WrapPersistent(transaction_.Get()))));
}

void IDBRequest::EnqueueResponse(DOMException* error) {
  IDB_TRACE("IDBRequest::EnqueueResponse(DOMException)");
  if (!ShouldEnqueueEvent()) {
    metrics_.RecordAndReset();
    return;
  }

  error_ = error;
  SetResult(MakeGarbageCollected<IDBAny>(IDBAny::kUndefinedType));
  pending_cursor_.Clear();
  EnqueueEvent(Event::CreateCancelableBubble(event_type_names::kError));
}

void IDBRequest::EnqueueResponse(const Vector<String>& string_list) {
  IDB_TRACE("IDBRequest::onSuccess(StringList)");
  if (!ShouldEnqueueEvent()) {
    metrics_.RecordAndReset();
    return;
  }

  auto* dom_string_list = MakeGarbageCollected<DOMStringList>();
  for (const auto& item : string_list)
    dom_string_list->Append(item);
  EnqueueResultInternal(MakeGarbageCollected<IDBAny>(dom_string_list));
}

void IDBRequest::EnqueueResponse(std::unique_ptr<WebIDBCursor> backend,
                                 std::unique_ptr<IDBKey> key,
                                 std::unique_ptr<IDBKey> primary_key,
                                 std::unique_ptr<IDBValue> value) {
  IDB_TRACE1("IDBRequest::EnqueueResponse(IDBCursor)", "size",
             value ? value->DataSize() : 0);
  if (!ShouldEnqueueEvent()) {
    metrics_.RecordAndReset();
    return;
  }

  DCHECK(!pending_cursor_);
  IDBCursor* cursor = nullptr;
  IDBObjectStoreOrIDBIndex source;

  if (source_.IsIDBObjectStore()) {
    source =
        IDBCursor::Source::FromIDBObjectStore(source_.GetAsIDBObjectStore());
  } else if (source_.IsIDBIndex()) {
    source = IDBCursor::Source::FromIDBIndex(source_.GetAsIDBIndex());
  }
  DCHECK(!source.IsNull());

  switch (cursor_type_) {
    case indexed_db::kCursorKeyOnly:
      cursor =
          MakeGarbageCollected<IDBCursor>(std::move(backend), cursor_direction_,
                                          this, source, transaction_.Get());
      break;
    case indexed_db::kCursorKeyAndValue:
      cursor = MakeGarbageCollected<IDBCursorWithValue>(
          std::move(backend), cursor_direction_, this, source,
          transaction_.Get());
      break;
    default:
      NOTREACHED();
  }
  SetResultCursor(cursor, std::move(key), std::move(primary_key),
                  std::move(value));
}

void IDBRequest::EnqueueResponse(std::unique_ptr<IDBKey> idb_key) {
  IDB_TRACE("IDBRequest::EnqueueResponse(IDBKey)");
  if (!ShouldEnqueueEvent()) {
    metrics_.RecordAndReset();
    return;
  }

  if (idb_key && idb_key->IsValid())
    EnqueueResultInternal(MakeGarbageCollected<IDBAny>(std::move(idb_key)));
  else
    EnqueueResultInternal(MakeGarbageCollected<IDBAny>(IDBAny::kUndefinedType));
}

namespace {
size_t SizeOfValues(const Vector<std::unique_ptr<IDBValue>>& values) {
  size_t size = 0;
  for (const auto& value : values)
    size += value->DataSize();
  return size;
}
}  // namespace

void IDBRequest::EnqueueResponse(Vector<std::unique_ptr<IDBValue>> values) {
  IDB_TRACE1("IDBRequest::EnqueueResponse([IDBValue])", "size",
             SizeOfValues(values));
  if (!ShouldEnqueueEvent()) {
    metrics_.RecordAndReset();
    return;
  }

  EnqueueResultInternal(MakeGarbageCollected<IDBAny>(std::move(values)));
}

#if DCHECK_IS_ON()
static IDBObjectStore* EffectiveObjectStore(const IDBRequest::Source& source) {
  if (source.IsIDBObjectStore())
    return source.GetAsIDBObjectStore();
  if (source.IsIDBIndex())
    return source.GetAsIDBIndex()->objectStore();

  NOTREACHED();
  return nullptr;
}
#endif  // DCHECK_IS_ON()

void IDBRequest::EnqueueResponse(std::unique_ptr<IDBValue> value) {
  IDB_TRACE1("IDBRequest::EnqueueResponse(IDBValue)", "size",
             value ? value->DataSize() : 0);
  if (!ShouldEnqueueEvent()) {
    metrics_.RecordAndReset();
    return;
  }

  if (pending_cursor_) {
    // Value should be null, signifying the end of the cursor's range.
    DCHECK(value->IsNull());
    DCHECK(!value->BlobInfo().size());
    pending_cursor_->Close();
    pending_cursor_.Clear();
  }

#if DCHECK_IS_ON()
  DCHECK(!value->PrimaryKey() ||
         value->KeyPath() == EffectiveObjectStore(source_)->IdbKeyPath());
#endif

  EnqueueResultInternal(MakeGarbageCollected<IDBAny>(std::move(value)));
}

void IDBRequest::EnqueueResponse(int64_t value) {
  IDB_TRACE("IDBRequest::EnqueueResponse(int64_t)");
  if (!ShouldEnqueueEvent()) {
    metrics_.RecordAndReset();
    return;
  }
  EnqueueResultInternal(MakeGarbageCollected<IDBAny>(value));
}

void IDBRequest::EnqueueResponse() {
  IDB_TRACE("IDBRequest::EnqueueResponse()");
  if (!ShouldEnqueueEvent()) {
    metrics_.RecordAndReset();
    return;
  }
  EnqueueResultInternal(MakeGarbageCollected<IDBAny>(IDBAny::kUndefinedType));
}

void IDBRequest::EnqueueResultInternal(IDBAny* result) {
  DCHECK(GetExecutionContext());
  DCHECK(!pending_cursor_);
  DCHECK(transit_blob_handles_.IsEmpty());
  SetResult(result);
  EnqueueEvent(Event::Create(event_type_names::kSuccess));
}

void IDBRequest::SetResult(IDBAny* result) {
  result_ = result;
  result_dirty_ = true;
}

void IDBRequest::EnqueueResponse(std::unique_ptr<IDBKey> key,
                                 std::unique_ptr<IDBKey> primary_key,
                                 std::unique_ptr<IDBValue> value) {
  IDB_TRACE("IDBRequest::EnqueueResponse(IDBKey, IDBKey primaryKey, IDBValue)");
  if (!ShouldEnqueueEvent()) {
    metrics_.RecordAndReset();
    return;
  }

  DCHECK(pending_cursor_);
  SetResultCursor(pending_cursor_.Release(), std::move(key),
                  std::move(primary_key), std::move(value));
  metrics_.RecordAndReset();
}

bool IDBRequest::HasPendingActivity() const {
  // FIXME: In an ideal world, we should return true as long as anyone has a or
  //        can get a handle to us and we have event listeners. This is order to
  //        handle user generated events properly.
  return has_pending_activity_ && GetExecutionContext();
}

void IDBRequest::ContextDestroyed() {
  if (ready_state_ == PENDING) {
    ready_state_ = kEarlyDeath;
    if (queue_item_)
      queue_item_->CancelLoading();
    if (transaction_)
      transaction_->UnregisterRequest(this);
  }

  if (source_.IsIDBCursor())
    source_.GetAsIDBCursor()->ContextWillBeDestroyed();
  if (result_)
    result_->ContextWillBeDestroyed();
  if (pending_cursor_)
    pending_cursor_->ContextWillBeDestroyed();
  if (web_callbacks_) {
    web_callbacks_->DetachRequestFromCallback();
    web_callbacks_ = nullptr;
  }
}

const AtomicString& IDBRequest::InterfaceName() const {
  return event_target_names::kIDBRequest;
}

ExecutionContext* IDBRequest::GetExecutionContext() const {
  return ExecutionContextLifecycleObserver::GetExecutionContext();
}

DispatchEventResult IDBRequest::DispatchEventInternal(Event& event) {
  IDB_TRACE("IDBRequest::dispatchEvent");

  event.SetTarget(this);

  HeapVector<Member<EventTarget>> targets;
  targets.push_back(this);
  if (transaction_ && !prevent_propagation_) {
    // Per spec: "A request's get the parent algorithm returns the request's
    // transaction."
    targets.push_back(transaction_);
    // Per spec: "A transaction's get the parent algorithm returns the
    // transaction's connection."
    targets.push_back(transaction_->db());
  }

  // If this event originated from script, it should have no side effects.
  if (!event.isTrusted())
    return IDBEventDispatcher::Dispatch(event, targets);
  DCHECK(event.type() == event_type_names::kSuccess ||
         event.type() == event_type_names::kError ||
         event.type() == event_type_names::kBlocked ||
         event.type() == event_type_names::kUpgradeneeded)
      << "event type was " << event.type();

  if (!GetExecutionContext())
    return DispatchEventResult::kCanceledBeforeDispatch;
  DCHECK_EQ(ready_state_, PENDING);
  DCHECK(has_pending_activity_);
  DCHECK_EQ(event.target(), this);

  if (event.type() != event_type_names::kBlocked)
    ready_state_ = DONE;

  // Cursor properties should not be updated until the success event is being
  // dispatched.
  IDBCursor* cursor_to_notify = nullptr;
  if (event.type() == event_type_names::kSuccess) {
    cursor_to_notify = GetResultCursor();
    if (cursor_to_notify) {
      cursor_to_notify->SetValueReady(std::move(cursor_key_),
                                      std::move(cursor_primary_key_),
                                      std::move(cursor_value_));
    }
  }

  if (event.type() == event_type_names::kUpgradeneeded) {
    DCHECK(!did_fire_upgrade_needed_event_);
    did_fire_upgrade_needed_event_ = true;
  }

  const bool set_transaction_active =
      transaction_ &&
      (event.type() == event_type_names::kSuccess ||
       event.type() == event_type_names::kUpgradeneeded ||
       (event.type() == event_type_names::kError && !request_aborted_));

  if (set_transaction_active)
    transaction_->SetActive(true);

  // The request must be unregistered from the transaction before the event
  // handler is invoked, because the handler can call an IDBCursor method that
  // reuses this request, like continue() or advance(). http://crbug.com/724109
  // describes the consequences of getting this wrong.
  if (transaction_ && ready_state_ == DONE)
    transaction_->UnregisterRequest(this);

  if (event.type() == event_type_names::kError && transaction_)
    transaction_->IncrementNumErrorsHandled();

  // Now that the event dispatching has been triggered, record that the metric
  // has completed.
  metrics_.RecordAndReset();

  DispatchEventResult dispatch_result =
      IDBEventDispatcher::Dispatch(event, targets);

  if (transaction_) {
    // Possibly abort the transaction. This must occur after unregistering (so
    // this request doesn't receive a second error) and before deactivating
    // (which might trigger commit).
    if (!request_aborted_) {
      // Transactions should be aborted after event dispatch if an exception was
      // not caught.
      if (event.LegacyDidListenersThrow()) {
        transaction_->SetError(MakeGarbageCollected<DOMException>(
            DOMExceptionCode::kAbortError,
            "Uncaught exception in event handler."));
        transaction_->abort(IGNORE_EXCEPTION_FOR_TESTING);
      } else if (event.type() == event_type_names::kError &&
                 dispatch_result == DispatchEventResult::kNotCanceled) {
        transaction_->SetError(error_);
        transaction_->abort(IGNORE_EXCEPTION_FOR_TESTING);
      }
    }

    // If this was the last request in the transaction's list, it may commit
    // here.
    if (set_transaction_active)
      transaction_->SetActive(false);
  }

  if (cursor_to_notify)
    cursor_to_notify->PostSuccessHandlerCallback();

  // An upgradeneeded event will always be followed by a success or error event,
  // so must be kept alive.
  if (ready_state_ == DONE && event.type() != event_type_names::kUpgradeneeded)
    has_pending_activity_ = false;

  return dispatch_result;
}

void IDBRequest::TransactionDidFinishAndDispatch() {
  DCHECK(transaction_);
  DCHECK(transaction_->IsVersionChange());
  DCHECK(did_fire_upgrade_needed_event_);
  DCHECK_EQ(ready_state_, DONE);
  DCHECK(GetExecutionContext());
  transaction_.Clear();

  if (!GetExecutionContext())
    return;

  ready_state_ = PENDING;
}

void IDBRequest::EnqueueEvent(Event* event) {
  DCHECK(ready_state_ == PENDING || ready_state_ == DONE);

  if (!GetExecutionContext())
    return;

  DCHECK(ready_state_ == PENDING || did_fire_upgrade_needed_event_)
      << "When queueing event " << event->type() << ", ready_state_ was "
      << ready_state_;

  event->SetTarget(this);

  event_queue_->EnqueueEvent(FROM_HERE, *event);
}

}  // namespace blink


text:
import { Controller } from '../../../..';

export default class SayController extends Controller {
  index(params, _cli) {
    console.log(`Hello ${params['name']}`); // eslint-disable-line no-console
    return 1;
  }
}


text:
<?php

interface Tribe__REST__Endpoints__UPDATE_Endpoint_Interface {
	/**
	 * Handles UPDATE requests on the endpoint.
	 *
	 * @param WP_REST_Request $request
	 *
	 * @return WP_Error|WP_REST_Response An array containing the data of the updated post on
	 *                                   success or a WP_Error instance on failure.
	 */
	public function update( WP_REST_Request $request );

	/**
	 * Returns the content of the `args` array that should be used to register the endpoint
	 * with the `register_rest_route` function.
	 *
	 * @return array
	 */
	public function EDIT_args();

	/**
	 * Whether the current user can update content of this type or not.
	 *
	 * @return bool Whether the current user can update or not.
	 */
	public function can_edit();
}


text:
USE [VipunenTK]
GO
/****** Object:  View [dbo].[v_f_tab_tyollisten_ammattisiirtymat]    Script Date: 9.3.2018 14:26:08 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'[dbo].[v_f_tab_tyollisten_ammattisiirtymat]'))
EXEC dbo.sp_executesql @statement = N'

CREATE VIEW [dbo].[v_f_tab_tyollisten_ammattisiirtymat] AS

SELECT
	  Tilastovuosi = f.tilastovuosi

	  --vanhat
      ,[Sukupuoli] = d1.sukupuoli
      ,[Äidinkieli_vanha] = d2a.aidinkieli_versio1
      ,[Työpaikan sijaintimaakunta] = d4.maakunta
      ,[Pääasiallinen toiminta siirtymän päässä_vanha] = d6a.paaasiallinen_toiminta
      ,[Työpaikan sijainti siirtymän päässä] = d7.tyopaikan_sijainti_v_tilastovuonna

	  --uudet
	  ,[Pääasiallinen toiminta] = d6b.paaasiallinen_toiminta_versio9
	  ,[Pääasiallinen toiminta siirtymän päässä] = d6c.paaasiallinen_toiminta_versio9
	  ,[Äidinkieli] = d2b.aidinkieli_versio5
	  ,[Toimiala] = d12.toimiala_2008
	  ,[Toimiala siirtymän päässä] = d13.toimiala_2008
	  ,[Toimiala sama kuin tilastovuonna] =
			case
				when d12.toimiala_2008=d13.toimiala_2008 then ''Toimiala sama kuin tilastovuonna''
				when d12.toimiala_2008<>d13.toimiala_2008 then ''Toimiala eri kuin tilastovuonna''
				else ''Tieto puuttuu''
			end
		--2002
	  ,[Koulutusaste 2002] = d14.koulutusaste_2002
	  ,[Koulutusala 2002] = d18.koulutusala2002
	  ,[Opintoala 2002] = d18.opintoala2002
	  ,[Koulutusaste 2002 siirtymän päässä] = case when d15.koulutusaste_2002 = ''Tuntematon'' then ''Ei uutta tutkintoa'' else d15.koulutusaste_2002 end
	  ,[Koulutusala 2002 siirtymän päässä] = case when d19.koulutusala2002 = ''Tuntematon'' then ''Ei uutta tutkintoa'' else d19.koulutusala2002 end
	  ,[Opintoala 2002 siirtymän päässä] = case when d19.opintoala2002 = ''Tuntematon'' then ''Ei uutta tutkintoa'' else  d19.opintoala2002 end
	  ,[Erikoistumiskoulutuksen koulutusala siirtymän päässä] = d27.koulutusala2002
	  ,[Erikoistumiskoulutuksen opintoala siirtymän päässä] = d27.opintoala2002
		--2016
	  ,[Koulutusaste, taso 1] = d16.iscle2011
	  ,[Koulutusaste, taso 2] = d16.Koulutusaste_taso2
	  ,[Koulutusala, taso 1] = d20.iscfinarrow2013
	  ,[Koulutusala, taso 2] = d20.iscfibroad2013
	  ,[Koulutusaste, taso 1 siirtymän päässä] = case when d17.iscle2011 = ''Tuntematon'' then ''Ei uutta tutkintoa'' else d17.iscle2011 end
	  ,[Koulutusaste, taso 2 siirtymän päässä] = case when d17.Koulutusaste_taso2 = ''Tuntematon'' then ''Ei uutta tutkintoa'' else d17.koulutusaste_taso2 end
	  ,[Koulutusala, taso 1 siirtymän päässä] = case when d21.iscfinarrow2013 = ''Tuntematon'' then ''Ei uutta tutkintoa'' else d21.iscfinarrow2013 end
	  ,[Koulutusala, taso 2 siirtymän päässä] = case when d21.iscfibroad2013 = ''Tuntematon'' then ''Ei uutta tutkintoa'' else d21.iscfibroad2013 end
	  ,[Koulutuslaji] = d22.ammatillisen_koulutuksen_koulutuslaji_tutkintorekisterissa
	  ,[Koulutuslaji siirtymän päässä] = case when d23.ammatillisen_koulutuksen_koulutuslaji_tutkintorekisterissa = ''Tuntematon'' then ''Ei uutta tutkintoa'' else d23.ammatillisen_koulutuksen_koulutuslaji_tutkintorekisterissa end
	  ,[Opettajankelpoisuus] = d24.kylla_ei
	  ,[Opettajankelpoisuus siirtymän päässä] = d25.kylla_ei
	  ,[Työpaikan sijaintimaakunta sama kuin tilastovuonna] = d26.kylla_ei

	  --yhteiset
	  ,[Ikäryhmä] = case when f.lahde = ''R4.23'' then d3.ika else d3.ika5v end
	  ,[Ammattiryhmä 1.taso] = d5.mitenna_ammattiryhma1
	  ,[Ammattiryhmä 2.taso] = d5.mitenna_ammattiryhma2
	  ,[Ammattiryhmä (1.taso) siirtymän päässä] = d8.mitenna_ammattiryhma1
	  ,[Ammattiryhmä (2.taso) siirtymän päässä] = d8.mitenna_ammattiryhma2
	  ,[Ammattiryhmä 1. taso sama kuin tilastovuonna] = case when d5.mitenna_ammattiryhma1=d8.mitenna_ammattiryhma1 then ''Ammattiryhmä 1. taso sama kuin tilastovuonna'' else ''Ammattiryhmä 1. taso eri kuin tilastovuonna'' end
	  ,[Ammattiryhmä 2. taso sama kuin tilastovuonna] = case when d5.mitenna_ammattiryhma2=d8.mitenna_ammattiryhma2 then ''Ammattiryhmä 2. taso sama kuin tilastovuonna'' else ''Ammattiryhmä 2. taso eri kuin tilastovuonna'' end
	  ,[Siirtymän tarkastelusuunta] =
			case d11.siirtyman_tarkastelusuunta
				when ''Siirtymän tarkastelusuunta ajassa eteenpäin'' then ''Ajassa eteenpäin''
				when ''Siirtymän tarkastelusuunta ajassa taaksepäin'' then ''Ajassa taaksepäin''
				else ''Tieto puuttuu''
			end
	  ,[Perusjoukko] = d10.perusjoukko_tyolliset
	  ,[Suhteellinen ajankohta] = d9.suhteellinen_ajankohta
	  ,[lkm]
	  ,[Lähde] = f.lahde

	  --järjestyskentät
	  ,[järjestys Sukupuoli ] = d1.jarjestys
	  ,[järjestys Äidinkieli vanha ] = d2a.jarjestys
	  ,[järjestys Ikä ] = d3.jarjestys_ika5v
	  ,[järjestys Maakunta ] = d4.jarjestys_maakunta
	  ,[järjestys Ammattiryhmä1 ] = d5.jarjestys_ammattiryhma1
	  ,[järjestys Ammattiryhmä2 ] = d5.jarjestys_ammattiryhma2
	  ,[järjestys Pääasiallinen toiminta vanha ] = d6a.jarjestys
	  ,[järjestys Työpaikan sijainti ] = d7.jarjestys
	  ,[järjestys Ammattiryhmä1 siirtymä ] = d8.jarjestys_ammattiryhma1
	  ,[järjestys Ammattiryhmä2 siirtymä ] = d8.jarjestys_ammattiryhma2
	  ,[järjestys Ajankohta ] = d9.jarjestys
	  ,[järjestys Perusjoukko ] = d10.jarjestys
	  ,[järjestys Siirtymä ] = d11.jarjestys
	  ,[järjestys Ammattiryhmä 1. taso sama kuin tilastovuonna ] = case when d5.mitenna_ammattiryhma1=d8.mitenna_ammattiryhma1 then 1 else 2 end
	  ,[järjestys Ammattiryhmä 2. taso sama kuin tilastovuonna ] = case when d5.mitenna_ammattiryhma2=d8.mitenna_ammattiryhma2 then 1 else 2 end
	  ,[järjestys Pääasiallinen toiminta] = d6b.jarjestys
	  ,[järjestys Pääasiallinen toiminta siirtymän päässä] = d6c.jarjestys
	  ,[järjestys Äidinkieli] = d2b.jarjestys
	  ,[järjestys Toimiala] = d12.jarjestys
	  ,[järjestys Toimiala siirtymän päässä] = d13.jarjestys
	  ,[järjestys Toimiala sama kuin tilastovuonna] =
			case
				when d12.toimiala_2008=d13.toimiala_2008 then 1
				when d12.toimiala_2008<>d13.toimiala_2008 then 2
				else 9
			end
	  ,[järjestys Koulutusaste 2002] = d14.jarjestys
	  ,[järjestys Koulutusaste 2002 siirtymän päässä] = d15.jarjestys
	  ,[järjestys Opintoala 2002] = d18.jarjestys_opintoala2002
	  ,[järjestys Opintoala 2002 siirtymän päässä] = d19.jarjestys_opintoala2002
	  ,[järjestys Koulutusala 2002] = d18.jarjestys_koulutusala2002
	  ,[järjestys Koulutusala 2002 siirtymän päässä] = d19.jarjestys_koulutusala2002
	  ,[järjestys Erikoistumiskoulutuksen koulutusala siirtymän päässä] = d27.jarjestys_koulutusala2002
	  ,[järjestys Erikoistumiskoulutuksen opintoala siirtymän päässä] = d27.jarjestys_opintoala2002
	  ,[järjestys Koulutusaste, taso 1] = d16.jarjestys_iscle2011
	  ,[järjestys Koulutusaste, taso 2] = d16.jarjestys_Koulutusaste_taso2
	  ,[järjestys Koulutusala, taso 1] = d20.jarjestys_iscfinarrow2013
	  ,[järjestys Koulutusala, taso 2] = d20.jarjestys_iscfibroad2013
	  ,[järjestys Koulutusaste, taso 1 siirtymän päässä] = d17.jarjestys_iscle2011
	  ,[järjestys Koulutusaste, taso 2 siirtymän päässä] = d17.jarjestys_Koulutusaste_taso2
	  ,[järjestys Koulutusala, taso 1 siirtymän päässä] = d21.jarjestys_iscfinarrow2013
	  ,[järjestys Koulutusala, taso 2 siirtymän päässä] = d21.jarjestys_iscfibroad2013
	  ,[järjestys Koulutuslaji] = d22.jarjestys
	  ,[järjestys Koulutuslaji siirtymän päässä] = d23.jarjestys
	  ,[järjestys Opettajankelpoisuus] = d24.jarjestys
	  ,[järjestys Opettajankelpoisuus siirtymän päässä] = d25.jarjestys
	  ,[järjestys Työpaikan sijaintimaakunta sama kuin tilastovuonna] = d26.jarjestys

  FROM [VipunenTK].[dbo].[f_tyollisten_ammattisiirtymat_ja_aiemmat_ammatit] f

  LEFT JOIN dbo.d_sukupuoli d1 on d1.id=f.sukupuoli_id
  LEFT JOIN dbo.d_aidinkieli_versio1 d2a on d2a.id=f.aidinkieli_versio1_id
  LEFT JOIN dbo.d_aidinkieli_versio5 d2b on d2b.id=f.aidinkieli_versio5_id
  LEFT JOIN dbo.d_ika d3 on d3.id=f.ika_id
  LEFT JOIN dbo.d_alueluokitus d4 on d4.id=f.tyopaikan_sijaintimaakunta_id
  LEFT JOIN dbo.d_mitenna_ammatti d5 on d5.id=f.mitenna_ammatti_id
  LEFT JOIN dbo.d_paaasiallinen_toiminta d6a on d6a.id=f.paaasiallinen_toiminta_siirtyman_paassa_id
  LEFT JOIN dbo.d_paaasiallinen_toiminta_versio9 d6b on d6b.id=f.paaasiallinen_toimintar9_id
  LEFT JOIN dbo.d_paaasiallinen_toiminta_versio9 d6c on d6c.id=f.paaasiallinen_toimintar9_siirtyman_paassa_id
  LEFT JOIN dbo.d_tyopaikan_sijainti_v_tilastovuonna d7 on d7.id=f.tyopaikan_sijainti_v_tilastovuonna_id
  LEFT JOIN dbo.d_mitenna_ammatti d8 on d8.id=f.mitenna_ammatti_siirtyman_paassa_id
  LEFT JOIN dbo.d_suhteellinen_ajankohta d9 on d9.id=f.suhteellinen_ajankohta_id
  LEFT JOIN dbo.d_perusjoukko_tyolliset d10 on d10.id=f.perusjoukko_tyolliset_id
  LEFT JOIN dbo.d_siirtyman_tarkastelusuunta d11 on d11.id=f.siirtyman_tarkastelusuunta_id
  LEFT JOIN dbo.d_toimiala_2008 d12 on d12.id=f.toimiala_id
  LEFT JOIN dbo.d_toimiala_2008 d13 on d13.id=f.toimiala_siirtyman_paassa_id
  LEFT JOIN dbo.d_koulutusaste_2002 d14 on d14.id=f.koulutusaste_vanha_id
  LEFT JOIN dbo.d_koulutusaste_2002 d15 on d15.id=f.koulutusaste_vanha_siirtyman_paassa_id
  LEFT JOIN dbo.d_koulutusluokitus d16 on d16.id=f.koulutusala_taso2_id
  LEFT JOIN dbo.d_koulutusluokitus d17 on d17.id=f.koulutusala_taso2_siirtyman_paassa_id
  LEFT JOIN dbo.d_koulutusluokitus d18 on d18.id=f.opintoala_id
  LEFT JOIN dbo.d_koulutusluokitus d19 on d19.id=f.opintoala_siirtyman_paassa_id
  LEFT JOIN dbo.d_koulutusluokitus d20 on d20.id=f.koulutusala_taso2_id
  LEFT JOIN dbo.d_koulutusluokitus d21 on d21.id=f.koulutusala_taso2_siirtyman_paassa_id
  LEFT JOIN dbo.d_ammatillisen_koulutuksen_koulutuslaji_tutkintorekisterissa d22 on d22.id=f.koulutuslaji_id
  LEFT JOIN dbo.d_ammatillisen_koulutuksen_koulutuslaji_tutkintorekisterissa d23 on d23.id=f.koulutuslaji_siirtyman_paassa_id
  LEFT JOIN dbo.d_kylla_ei d24 on d24.id=f.opettajankelpoisuus_id
  LEFT JOIN dbo.d_kylla_ei d25 on d25.id=f.opettajankelpoisuus_siirtyman_paassa_id
  LEFT JOIN dbo.d_kylla_ei d26 on d26.id=f.tyopaikan_sijaintimaakunta_sama_kylla_ei_id
  LEFT JOIN dbo.d_koulutusluokitus d27 on d27.id=f.opintoala_erikoistumiskoulutus_siirtyman_paassa_id

'
GO

USE [ANTERO]


text: <div link-event-details event-id="eventId" event-name="eventName"></div>


text:
require "priceable/version"

module Priceable
  SUFFIXES = ["_in_cents", "_in_pennies", "_as_integer"]
  def priceable(*price_fields)
    price_fields.each do |price_field|
      suffix = SUFFIXES.detect { |suffix| self.attribute_method? "#{price_field}#{suffix}".to_sym }
      #raise ArgumentError, "Unable to find valid database field for `#{price_field}'" unless suffix
      next unless suffix # raise error will cause the migration break.
      define_method price_field do
        unless send("#{price_field}#{suffix}".to_sym).nil?
          send("#{price_field}#{suffix}".to_sym) / 100.0
        else
          0.0
        end
      end
      define_method "#{price_field}=".to_sym do |new_price|
        send("#{price_field}#{suffix}=".to_sym, (new_price.to_f * 100).round)
      end
    end

    unless Rails::VERSION::MAJOR == 4 && !defined?(ProtectedAttributes)
      if self._accessible_attributes?
        attr_accessible *price_fields
      end
    end

  end
end

ActiveRecord::Base.send(:extend, Priceable)