text:
package ai.clipper.spark

import java.net.URLClassLoader
import java.nio.file.StandardCopyOption.REPLACE_EXISTING
import java.nio.file.StandardOpenOption.CREATE
import java.nio.file.{Files, Paths}
import java.nio.charset.Charset

import org.apache.spark.SparkContext
import org.apache.spark.ml.PipelineModel
import org.json4s._
import org.json4s.jackson.Serialization.{read, write}
import org.json4s.jackson.Serialization

import scalaj.http._

import scala.sys.process._

sealed trait ModelType extends Serializable

case object MLlibModelType extends ModelType

case object PipelineModelType extends ModelType

object ModelTypeSerializer
    extends CustomSerializer[ModelType](
      _ =>
        (
          {
            case JString("MLlibModelType") => MLlibModelType
            case JString("PipelineModelType") => PipelineModelType
          }, {
            case MLlibModelType => JString("MLlibModelType")
            case PipelineModelType => JString("PipelineModelType")
          }
      ))

class UnsupportedEnvironmentException(e: String) extends RuntimeException(e)

class ModelDeploymentError(e: String) extends RuntimeException(e)

case class ClipperContainerConf(var className: String,
                                var jarName: String,
                                var modelType: ModelType,
                                var fromRepl: Boolean = false,
                                var replClassDir: Option[String] = None)

object Clipper {

  val CLIPPER_CONF_FILENAME: String = "clipper_conf.json"
  val CONTAINER_JAR_FILE: String = "container_source.jar"
  val MODEL_DIRECTORY: String = "model"
  val REPL_CLASS_DIR: String = "repl_classes"
  val CLIPPER_SPARK_CONTAINER_NAME = "clipper/spark-scala-container"

  val DOCKER_NW: String = "clipper_nw"
  val CLIPPER_MANAGEMENT_PORT: Int = 1338

  val CLIPPER_DOCKER_LABEL: String = "ai.clipper.container.label";

  // Imports the json serialization library as an implicit and adds our custom serializer
  // for the ModelType case classes
  implicit val json4sFormats = Serialization.formats(NoTypeHints) + ModelTypeSerializer

  /**
    *
    * @param sc Spark context
    * @param name The name to assign the model when deploying to Clipper
    * @param version The model version
    * @param model The trained Spark model. Note that this _must_ be an instance of either
    *              ai.clipper.spark.MLlibModel or org.apache.spark.ml.PipelineModel
    * @param containerClass The model container which specifies how to use the trained
    *                       model to make predictions. This can include any pre-processing
    *                       or post-processing code (including any featurization). This class
    *                       must either extend ai.clipper.spark.MLlibContainer or
    *                       ai.clipper.spark.PipelineModelContainer.
    * @param clipperHost The IP address or hostname of a running Clipper instance. This can be either localhost
    *                    or a remote machine that you have SSH access to. SSH access is required to copy the model and
    *                    launch a Docker container on the remote machine.
    * @param labels A list of labels to be associated with the model.
    * @param sshUserName If deploying to a remote machine, the username associated with the SSH credentials.
    * @param sshKeyPath If deploying to a remote machine, the path to an SSH key authorized to log in to the remote
    *                   machine.
    * @param dockerRequiresSudo True if the Docker daemon on the machine hosting Clipper requires sudo to access. If
    *                           set to true, the ssh user you specify must have passwordless sudo access.
    * @tparam M The type of the model. This _must_ be an instance of either
    *              ai.clipper.spark.MLlibModel or org.apache.spark.ml.PipelineModel
    */
  def deploySparkModel[M](sc: SparkContext,
                          name: String,
                          version: Int,
                          model: M,
                          containerClass: Class[_],
                          clipperHost: String,
                          labels: List[String],
                          sshUserName: Option[String] = None,
                          sshKeyPath: Option[String] = None,
                          dockerRequiresSudo: Boolean = true): Unit = {
    val basePath = Paths.get("/tmp", name, version.toString).toString
    // Use the same directory scheme of /tmp/<name>/<version> on host
    val hostDataPath = basePath
    val localHostNames = Set("local", "localhost", "127.0.0.1")
    val islocalHost = localHostNames.contains(clipperHost.toLowerCase())

    try {
      saveSparkModel[M](sc, name, version, model, containerClass, basePath)
      if (!islocalHost) {
        // Make sure that ssh credentials were supplied
        val (user, key) = try {
          val user = sshUserName.get
          val key = sshKeyPath.get
          (user, key)
        } catch {
          case _: NoSuchElementException => {
            val err =
              "SSH user name and keypath must be supplied to deploy model to remote Clipper instance"
            println(err)
            throw new ModelDeploymentError(err)
          }
        }
        copyModelDataToHost(clipperHost, basePath, hostDataPath, user, key)
        publishModelToClipper(clipperHost, name, version, labels, hostDataPath)
        startSparkContainerRemote(name,
                                  version,
                                  clipperHost,
                                  hostDataPath,
                                  user,
                                  key,
                                  dockerRequiresSudo)
      } else {
        publishModelToClipper(clipperHost, name, version, labels, hostDataPath)
        startSparkContainerLocal(name, version, basePath)
      }
    } catch {
      case e: Throwable => {
        println(s"Error saving model: ${e.printStackTrace}")
        return
      }
    }
  }

  private def startSparkContainerLocal(name: String,
                                       version: Int,
                                       modelDataPath: String): Unit = {
    println(s"MODEL_DATA_PATH: $modelDataPath")
    val startContainerCmd = Seq(
      "docker",
      "run",
      "-d",
      s"--network=$DOCKER_NW",
      "-v", s"$modelDataPath:/model:ro",
      "-e", s"CLIPPER_MODEL_NAME=$name",
      "-e", s"CLIPPER_MODEL_VERSION=$version",
      "-e", "CLIPPER_IP=query_frontend",
      "-e", "CLIPPER_INPUT_TYPE=doubles",
      "-l", s"$CLIPPER_DOCKER_LABEL",
      CLIPPER_SPARK_CONTAINER_NAME
    )
    if (startContainerCmd.! != 0) {
      throw new ModelDeploymentError("Error starting model container")
    }
  }

  private def startSparkContainerRemote(name: String,
                                        version: Int,
                                        clipperHost: String,
                                        modelDataPath: String,
                                        sshUserName: String,
                                        sshKeyPath: String,
                                        dockerRequiresSudo: Boolean): Unit = {

    val sudoCommand = if (dockerRequiresSudo) Seq("sudo") else Seq()
    val getDockerIPCommand = sudoCommand ++ Seq(
      "docker",
      "ps", "-aqf",
      "ancestor=clipper/query_frontend",
      "|", "xargs") ++ sudoCommand ++ Seq("docker",
      "inspect",
      "--format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}'"
    )

    val sshCommand = Seq("ssh",
      "-o", "StrictHostKeyChecking=no",
      "-i", s"$sshKeyPath",
      s"$sshUserName@$clipperHost")

    val dockerIpCommand = sshCommand ++ getDockerIPCommand
    val dockerIp = dockerIpCommand.!!.stripLineEnd
    println(s"Docker IP: $dockerIp")

    val startContainerCmd = sudoCommand ++ Seq(
      "docker",
      "run",
      "-d",
      s"--network=$DOCKER_NW",
      "-v", s"$modelDataPath:/model:ro",
      "-e", s"CLIPPER_MODEL_NAME=$name",
      "-e", s"CLIPPER_MODEL_VERSION=$version",
      "-e", s"CLIPPER_IP=$dockerIp",
      "-e", "CLIPPER_INPUT_TYPE=doubles",
      "-l", s"$CLIPPER_DOCKER_LABEL",
      CLIPPER_SPARK_CONTAINER_NAME
    )
    val sshStartContainerCmd = sshCommand ++ startContainerCmd
    println(sshStartContainerCmd)
    if (sshStartContainerCmd.! != 0) {
      throw new ModelDeploymentError("Error starting model container")
    }
  }

  private def publishModelToClipper(host: String,
                                    name: String,
                                    version: Int,
                                    labels: List[String],
                                    hostModelDataPath: String): Unit = {
    val data = Map(
      "model_name" -> name,
      "model_version" -> version,
      "labels" -> labels,
      "input_type" -> "doubles",
      "container_name" -> CLIPPER_SPARK_CONTAINER_NAME,
      "model_data_path" -> hostModelDataPath
    )
    val jsonData = write(data)

    val response = Http(s"http://$host:$CLIPPER_MANAGEMENT_PORT/admin/add_model")
      .header("Content-type", "application/json")
      .postData(jsonData)
      .asString

    if (response.code == 200) {
      println("Successfully published model to Clipper")
    } else {
      throw new ModelDeploymentError(
        s"Error publishing model to Clipper. ${response.code}: ${response.body}")
    }
  }

  private def copyModelDataToHost(host: String,
                                  localPath: String,
                                  destPath: String,
                                  sshUserName: String,
                                  sshKeyPath: String): Unit = {

    val mkdirCommand = Seq("ssh",
                           "-o", "StrictHostKeyChecking=no",
                           "-i", s"$sshKeyPath",
                           s"$sshUserName@$host",
                           "mkdir", "-p", destPath)
    val copyCommand = Seq("rsync",
                          "-r",
                          "-e", s"ssh -i $sshKeyPath -o StrictHostKeyChecking=no",
                          s"$localPath/",
                          s"$sshUserName@$host:$destPath")
    if (!(mkdirCommand.! == 0 && copyCommand.! == 0)) {
        throw new ModelDeploymentError(
        "Error copying model data to Clipper host")
    }
  }

  private[clipper] def saveSparkModel[M](sc: SparkContext,
                                         name: String,
                                         version: Int,
                                         model: M,
                                         containerClass: Class[_],
                                         basePath: String): Unit = {
    // Check that Spark is not running in the REPL
    if (getReplOutputDir(sc).isDefined) {
      throw new UnsupportedEnvironmentException(
        "Clipper cannot deploy models from Spark Shell")
    }
    val modelPath = Paths.get(basePath, MODEL_DIRECTORY).toString
    val modelType = model match {
      case m: MLlibModel => {
        m.save(sc, modelPath)
        // Because I'm not sure how to do it in the type system, check that
        // the container is of the right type
        // NOTE: this test doesn't work from the REPL
        try {
          containerClass.newInstance.asInstanceOf[MLlibContainer]
        } catch {
          case e: ClassCastException => {
            throw new IllegalArgumentException(
              "Error: Container must be a subclass of MLlibContainer")
          }
        }
        MLlibModelType
      }
      case p: PipelineModel => {
        p.save(modelPath)
        // Because I'm not sure how to do it in the type system, check that
        // the container is of the right type
        try {
          containerClass.newInstance.asInstanceOf[PipelineModelContainer]
        } catch {
          case e: ClassCastException => {
            throw new IllegalArgumentException(
              "Error: Container must be a subclass of PipelineModelContainer")
          }
        }
        PipelineModelType
      }
      case _ =>
        throw new IllegalArgumentException(
          s"Illegal model type: ${model.getClass.getName}")
    }
    val jarPath = Paths.get(
      containerClass.getProtectionDomain.getCodeSource.getLocation.getPath)
    val copiedJarName = CONTAINER_JAR_FILE
    println(s"JAR path: $jarPath")
    System.out.flush()
    Files.copy(jarPath, Paths.get(basePath, copiedJarName), REPLACE_EXISTING)
    val conf =
      ClipperContainerConf(containerClass.getName, copiedJarName, modelType)
    getReplOutputDir(sc) match {
      case Some(classSourceDir) => {
        throw new UnsupportedOperationException("Clipper does not support deploying models directly from the Spark REPL")
        // NOTE: This commented out code is intentionally committed. We hope to support
        // model deployment in the future.
//        println(
//          "deployModel called from Spark REPL. Saving classes defined in REPL.")
//        conf.fromRepl = true
//        conf.replClassDir = Some(REPL_CLASS_DIR)
//        val classDestDir = Paths.get(basePath, REPL_CLASS_DIR)
//        FileUtils.copyDirectory(Paths.get(classSourceDir).toFile,
//                                classDestDir.toFile)
      }
      case None =>
        println(
          "deployModel called from script. No need to save additionally generated classes.")
    }
    Files.write(Paths.get(basePath, CLIPPER_CONF_FILENAME),
                write(conf).getBytes,
                CREATE)
  }

  private def getReplOutputDir(sc: SparkContext): Option[String] = {
    sc.getConf.getOption("spark.repl.class.outputDir")
  }

  private[clipper] def loadSparkModel(
      sc: SparkContext,
      basePath: String): SparkModelContainer = {
    val confString = Files
      .readAllLines(Paths.get(basePath, CLIPPER_CONF_FILENAME),
                    Charset.defaultCharset())
      .get(0)

    val conf = read[ClipperContainerConf](confString)
    val classLoader = getClassLoader(basePath, conf)
    val modelPath = Paths.get(basePath, MODEL_DIRECTORY).toString
    println(s"Model path: $modelPath")

    conf.modelType match {
      case MLlibModelType => {
        val model = MLlibLoader.load(sc, modelPath)
        try {
          val container = classLoader
            .loadClass(conf.className)
            .newInstance()
            .asInstanceOf[MLlibContainer]
          container.init(sc, model)
          container.asInstanceOf[SparkModelContainer]
        } catch {
          case e: Throwable => {
            e.printStackTrace
            throw e
          }

        }
      }
      case PipelineModelType => {
        val model = PipelineModel.load(modelPath)
        try {
        val container = classLoader
          .loadClass(conf.className)
          .newInstance()
          .asInstanceOf[PipelineModelContainer]
        container.init(sc, model)
        container.asInstanceOf[SparkModelContainer]
        } catch {
          case e: Throwable => {
            e.printStackTrace
            throw e
          }
        }
      }
    }
  }

  private def getClassLoader(path: String,
                             conf: ClipperContainerConf): ClassLoader = {
    new URLClassLoader(Array(Paths.get(path, conf.jarName).toUri.toURL),
                       getClass.getClassLoader)
  }
}


text:
#include <fancontroller.h>

uint16_t fan1Current = 0;
uint16_t fan2Current = 0;
uint16_t fan3Current = 0;
uint16_t fan4Current = 0;
uint16_t fan5Current = 0;

uint16_t fan1CurrentMaxSpeed = 0;
uint16_t fan2CurrentMaxSpeed = 0;
uint16_t fan3CurrentMaxSpeed = 0;
uint16_t fan4CurrentMaxSpeed = 0;
uint16_t fan5CurrentMaxSpeed = 0;

uint8_t connectedFans = 0;

uint8_t currentChannel[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t	LEDColours[10][4] = {
		  {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
	}; //Array holding current colour of all LED's, as well as a dimmer channel
uint8_t	buffer[10][4] = {
		  {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
		, {0, 0, 0, 0}
	}; //Array holding current colour of all LED's, used in sweeping the LED's

//Map of linear intensities to Gamma-corrected values
uint8_t gammaMap[8] = {0, 2, 4, 5, 6, 7};

int main (void) {

	cli();
	setup();
	setColour(0,  3, 3, 3, 0);
	setColour(1,  3, 3, 3, 0);
	setColour(2,  3, 3, 3, 0);
	setColour(3,  3, 3, 3, 0);
	setColour(4,  3, 3, 3, 0);
	setColour(5,  3, 3, 3, 0);
	setColour(6,  3, 3, 3, 0);
	setColour(7,  3, 3, 3, 0);
	setColour(8,  3, 3, 3, 0);
	setColour(9,  3, 3, 3, 0);
	refreshDisplay();
	startup();
	sei();

	//Testcolours

	//uint32_t shiftBit = 0x80000000; //Test light :)
	//shiftout(shiftBit);

	while(1){

		/*
		for(uint8_t dimmer=0; dimmer<8; dimmer++){

			for(uint8_t colour=0; colour<8; colour++){

				setColour(1, colour, 0, 0, dimmer); //red
				setColour(3, 0, colour, 0, dimmer); //red
				setColour(5, 0, 0, colour, dimmer); //red

				setColour(2, colour, dimmer, 0, 0); //yellow
				setColour(4, 0, colour, dimmer, 0); //cyan

				setColour(6, colour, colour, dimmer, 0);
				setColour(7, dimmer, colour, dimmer, 0);
				setColour(8, dimmer, 0, colour, 0);

				PORTC ^= _BV(PORTC5); //toggle indicator
				_delay_ms(500);

			}

		}
		*/

		/*
		//testing rotary encoder input, moving through LEDs
		if( (PINB>>PINB4 & 1) != 1 ){
			if( shiftBit>>31 & 1){
				shiftBit = 0x00000004; //Move to other end
			} else{
				shiftBit <<= 1; //Move one to the right
			}
			_delay_ms(DEBOUNCETURN);
		}
		if( (PINB>>PINB5 & 1) != 1 ){
			if( shiftBit>>2 & 1){
				shiftBit = 0x80000000; //Move to other end
			} else{
				shiftBit >>= 1; //Move one to the right
			}
			_delay_ms(DEBOUNCETURN);
		}
		if( (PINB>>PINB0 & 1) != 1 ){
			if( shiftBit>>31 & 1){
				shiftBit = 0x00000004; //Move to end
			} else{
				shiftBit = 0x80000000; //Move to begining
			}
			_delay_ms(DEBOUNCEBUTTON);
		}

		shiftout(shiftBit);
		*/

	//Rotary encoder input
	//TODO

	} //while

}

void setup(void) {

	//cli(); //Disable interrupts temoprarily

		//Set prescaler to 1 (16MHz)
			CLKPR = _BV(CLKPCE);
			CLKPR = 0;

		//Timer 0-2 for PWM
			//Configure pins as outputs
			DDRD |= _BV(DDD5) | _BV(DDD6);
			DDRB |= _BV(DDB1) | _BV(DDB2) | _BV(DDB3);

			//Set prescalers to 1/256 of I/O clock
			TCCR0B |= _BV(CS02); //Timer0 Prescaler
			TCCR1B |= _BV(CS12); //Timer1 Prescaler
			TCCR2B |= _BV(CS22) | _BV(CS21); //Timer2 Prescaler

			//Set fast-PWM mode
				//Timer0 PWM settings
				TCCR0A |= _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00) | _BV(WGM01);
				//Timer1 PWM settings - 8BIT timer mode
				TCCR1A |= _BV(COM1A1) | _BV(COM1B1) | _BV(WGM10);
				TCCR1B |= _BV(WGM12);
				//Timer2 PWM settings (only OC2A used as output)
				TCCR2A |= _BV(COM2A1) | _BV(WGM20) | _BV(WGM21);

			//Enable interrupt for Timer2 overflow and half way (used for LED updates)
				OCR2B = 128; //Half way point
				TIMSK2 |= _BV(TOIE2) | _BV(OCIE2B); //Enable interrupts for overflow and halfway

		//Set inputs for rotary encoder - all inputs with pull-ups
			//PB0/P14 button, PB4/P18 Left. PB5/P19 Right
			PORTB |= _BV(PORTB0) | _BV(PORTB4) | _BV(PORTB5); //Activate pullups

		//Set Outputs for shift register
			DDRD |= _BV(DDD0) |	_BV(DDD1) |	_BV(DDD2) |	_BV(DDD3) |	_BV(DDD4);
			PORTD |= _BV(PORTD2); //avoid clear!
			PORTD &= ~(_BV(PORTD4)); //Enable output

		//Disable pin 28 / PC6 by enabling internal pull-up (in input configuration)
			DDRC |= _BV(DDC5); //Currently used as power on signal
			PORTC |= _BV(PORTC5);
		//Disable pin 13 by enabling internal pull-up
			PORTD |= _BV(PORTD7);

		//ADC configuration
			//ADMUX: REFS1 & REFS0 set to 0 as standard, so external AREF pin is used as reference
			ADCSRA |= _BV(ADPS0) | _BV(ADPS1) | _BV(ADPS2); //Set prescaler to 128 (125 kHz)
			ADCSRA |= _BV(ADEN); //Enable ADC
			ADCSRA |= _BV(ADSC); //Make an empty conversion to initiate ADC
			while(ADCSRA>>ADSC & 1); //Wait until conversion is finished

			//Disable digital inputs on Analog pins
			DIDR0 |= _BV(ADC0D) | _BV(ADC1D) | _BV(ADC2D) | _BV(ADC3D) | _BV(ADC4D);

	//sei(); //Enable interrupts again

}

/*
	Startup routine
		Sets all fans to 100% in order to ensure adequate startup power
		Records the fans current consumption at 100% speed
		Stores connection status
*/
void startup(void) {

	//Activate all fans on full speed
	OCR0A = ~(0); //Fan #1
	OCR0B = ~(0); //Fan #2
	OCR1AL = ~(0); //Fan #3
	OCR1BL = ~(0); //Fan #4
	OCR2A = ~(0); //Fan #5

	//Let fans spin to full speed

	//Blinking status light
	uint8_t time = STARTUPFANWARMINGINDICATORINTERVAL;

	for(int i=0; i<=STARTUPFANWARMINGPERIOD;){

		PORTC ^= _BV(PORTC5);
		_delay_ms(time);
		i += time;

	}

	//Store connection status
	checkConnections();

	PORTC &= ~(_BV(PORTC5)); //Ensure that the LED is off

}

/*
	Helper method to read and return a voltage for a sepcific fan
	Fan channels are recorded in macros FANxCH in .h file for easy reference
*/
uint16_t readFanCurrent(uint8_t chADC) {

	//Adjust analog channel in ADMUX
	switch(chADC) {

		case FAN1CH:
			//ADC0
			ADMUX &= ~(_BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0));
			break;

		case FAN2CH:
			//ADC1
			ADMUX &= ~(_BV(MUX3) | _BV(MUX2) | _BV(MUX1));
			ADMUX |= _BV(MUX0);
			break;

		case FAN3CH:
			//ADC2
			ADMUX &= ~(_BV(MUX3) | _BV(MUX2) | _BV(MUX0));
			ADMUX |= _BV(MUX1);
			break;

		case FAN4CH:
			//ADC3
			ADMUX &= ~(_BV(MUX3) | _BV(MUX2));
			ADMUX |= _BV(MUX1) | _BV(MUX0);
			break;

		case FAN5CH:
			//ADC4
			ADMUX &= ~(_BV(MUX3) | _BV(MUX1) | _BV(MUX0));
			ADMUX |= _BV(MUX2);
			break;

	}

	ADCSRA |=_BV(ADSC); //Starts conversion

	while( ADCSRA>>ADSC & 1 ); //Waits for conversion to finish

	uint16_t out = 0;
	out = ADCH<<sizeof(ADCL); //Move bit 9 & 10 to the left
	out |= ADCL; //Store the lower 8 bits

	return out;

}

/*
	Helper method to record connection status of all fans
	Turns on all unconnected channels and checks for new fan additions
*/
void checkConnections(void) {

	//TODO rewrite these segments to use universal logic

	/*
		----- FAN CHANNEL 1 -----
	*/

		//Check if this output has a newly connected fan
		if((connectedFans>>FAN1CONN & 1) != 0){

			//Check if there is any current draw with output on
			OCR0A = 255; //Turn on fan at full speed
			DDRD |= _BV(DDD5); //Turn on output
			_delay_us(UNCONNECTEDFANSTARTUPTIME); //Wait for output to turn on
			fan1Current = readFanCurrent(FAN1CH);

		} else {

			//TODO: match this with current timer status; otherwise, we might measure with output off!
			fan1Current = readFanCurrent(FAN1CH);

		}

		if( fan1Current < CONNECTIONTHRESHOLD ){

			connectedFans &= ~(_BV(FAN1CONN)); //unset bit
			OCR0A = 0; //Reset timer
			DDRD &= ~(_BV(DDD5)); //Turn off output

		}

	/*
		----- FAN CHANNEL 2 -----
	*/

		//Check if this output has a newly connected fan
		if((connectedFans>>FAN2CONN & 1) != 0){

			//Check if there is any current draw with output on
			OCR0B = 255; //Turn on fan at full speed
			DDRD |= _BV(DDD6); //Turn on output
			_delay_us(UNCONNECTEDFANSTARTUPTIME); //Wait for output to turn on
			fan2Current = readFanCurrent(FAN2CH);

		} else {

			//TODO: match this with current timer status; otherwise, we might measure with output off!
			fan2Current = readFanCurrent(FAN2CH);

		}

		if( fan2Current < CONNECTIONTHRESHOLD ){

			connectedFans &= ~(_BV(FAN2CONN)); //unset bit
			OCR0B = 0; //Reset timer
			DDRD &= ~(_BV(DDD6)); //Turn off output

		}

	/*
		----- FAN CHANNEL 3 -----
	*/

		//Check if this output has a newly connected fan
		if((connectedFans>>FAN3CONN & 1) != 0){

			//Check if there is any current draw with output on
			OCR1AL = 255; //Turn on fan at full speed
			DDRB |= _BV(DDB1); //Turn on output
			_delay_us(UNCONNECTEDFANSTARTUPTIME); //Wait for output to turn on
			fan3Current = readFanCurrent(FAN3CH);

		} else {

			//TODO: match this with current timer status; otherwise, we might measure with output off!
			fan3Current = readFanCurrent(FAN3CH);

		}

		if( fan3Current < CONNECTIONTHRESHOLD ){

			connectedFans &= ~(_BV(FAN3CONN)); //unset bit
			OCR1AL = 0; //Reset timer
			DDRB &= ~(_BV(DDB1)); //Turn off output

		}

	/*
		----- FAN CHANNEL 4 -----
	*/

		//Check if this output has a newly connected fan
		if((connectedFans>>FAN4CONN & 1) != 0){

			//Check if there is any current draw with output on
			OCR1BL = 255; //Turn on fan at full speed
			DDRB |= _BV(DDB2); //Turn on output
			_delay_us(UNCONNECTEDFANSTARTUPTIME); //Wait for output to turn on
			fan4Current = readFanCurrent(FAN4CH);

		} else {

			//TODO: match this with current timer status; otherwise, we might measure with output off!
			fan4Current = readFanCurrent(FAN4CH);

		}

		if( fan4Current < CONNECTIONTHRESHOLD ){

			connectedFans &= ~(_BV(FAN4CONN)); //unset bit
			OCR1BL = 0; //Reset timer
			DDRB &= ~(_BV(DDB2)); //Turn off output

		}

	/*
		----- FAN CHANNEL 5 -----
	*/

		//Check if this output has a newly connected fan
		if((connectedFans>>FAN5CONN & 1) != 0){

			//Check if there is any current draw with output on
			OCR2A = 255; //Turn on fan at full speed
			DDRB |= _BV(DDB3); //Turn on output
			_delay_us(UNCONNECTEDFANSTARTUPTIME); //Wait for output to turn on
			fan5Current = readFanCurrent(FAN5CH);

		} else {

			//TODO: match this with current timer status; otherwise, we might measure with output off!
			fan5Current = readFanCurrent(FAN5CH);

		}

		if( fan5Current < CONNECTIONTHRESHOLD ){

			connectedFans &= ~(_BV(FAN5CONN)); //unset bit
			OCR2A = 0; //Reset timer
			DDRB &= ~(_BV(DDB3)); //Turn off output

		}

}

/*
	Refresh LED's
		Each of the 10 LED's uses 3 channels (RGB)
		Each colour channel is 3 bits long (values ranging from 0-7)

		The logic is optimized to always never leave gaps in when possible, i.e. to maximze brightness
		Therefore, the values in the array does not represent true bit values,
		but more of relationships between colours: how bright they are in relation to the others.
		//TODO: this will be remedied in the future, to allow for a more common RGB(a,b,c) format

		There is a fourth channel available to dim the LED, if this is required.
		Writing to this channel will output 0 to the shift register
		//TODO: this should be set automatically by the setColour method in the future
*/
void refreshDisplay(void){

	//Prepare output to display
	uint32_t output = 0;
	uint32_t bitValue = 0;
	uint8_t channel = 0;
	uint8_t channelSearch = 0;

	for( int8_t led=0; led<10; led++ ){

		//find the channel to display if current channel i empty
		if( buffer[led][currentChannel[led]] == 0 ){

			channelSearch = currentChannel[led];

			while(1){

				if( channelSearch >= DIMMER ){ //start search from the beginning
					channelSearch = RED;
				} else {
					channelSearch += 1;
				}

				if( buffer[led][channelSearch] > 0){

					//We found a channel with remaining value, set this to the active channel!
					currentChannel[led] = channelSearch;
					break;

				} else if( channelSearch == currentChannel[led] ){

					//nothing to display (we have looped all channels once) - copy new value to buffer again
					copyToBuffer(led);

					//Set the LED to black until we have new data
					currentChannel[led] = DIMMER;
					break;

				}

			} //while

		}

		//Set the channel to display
		channel = currentChannel[led];

		//Reduce value in buffer
		if( buffer[led][currentChannel[led]] != 0 ){
			buffer[led][currentChannel[led]] -= 1;
		}

		/*
			Advance to the next colour (done to avoid flickering).
			This guesses that the next channel contains data, but this will be checked in the next refresh cycle
		*/
		if( currentChannel[led] == DIMMER ){
			currentChannel[led] = RED;
		} else {
			currentChannel[led] += 1;
		}

		if(channel != DIMMER){ //push no data if the channel is empty -- already 0 for all LED outputs

			bitValue = 1;

			//These are a bit ugly, but I couldn't figure out how to shift according to a variable value #CNoobProblems
			for( uint8_t shiftTimes=2; shiftTimes>channel; shiftTimes-- ){

				//Shift to the correct LED channel
				bitValue <<= 1;

			}

			for( uint8_t shiftTimes=0; shiftTimes<(9-led); shiftTimes++ ){

				//Shift the output 3 times to the right for each LED (RGB LED)
				bitValue <<= 3; //Shift value to correct position

			}

			output |= bitValue; //Merge the bit with the output

		}

	}

	shiftout(output<<SHIFTREGISTEREMPTYBITS);

}

/*
	Copies LEDColours data into the buffer, which is used for keeping track of screen refresh

	Returns:
		0 if no bytes was copied
		>=1 if data was copied
*/
uint8_t copyToBuffer(uint8_t led){

	uint8_t bitsum = LEDColours[led][0] + LEDColours[led][1] + LEDColours[led][2] + LEDColours[led][3];

	//Don't bother copying anything if there is nothing to copy //TODO this is probably less efficient
	if(bitsum > 0){

		for( uint8_t i=0;  i<4; i++ ){
			buffer[led][i] = LEDColours[led][i]; //Copy to buffer
		}

	}

	return bitsum;

}

/*
	Method to update the led colours array

	This method is used to trim the values to reasonable limits
	Maximum bit value is set in h file

	//TODO: this should be gamma corrected. How many bits are needed then?
*/
void setColour(uint8_t led, uint8_t redCh, uint8_t greenCh, uint8_t blueCh, uint8_t dimmerCh){

	if( redCh > MAXCHANNELVALUE ){
		redCh = MAXCHANNELVALUE;
	}
	if( greenCh > MAXCHANNELVALUE ){
		greenCh = MAXCHANNELVALUE;
	}
	if( blueCh > MAXCHANNELVALUE ){
		blueCh = MAXCHANNELVALUE;
	}
	if( dimmerCh > MAXCHANNELVALUE ){
		dimmerCh = MAXCHANNELVALUE;
	}

	//Copy gamma-corrected values to the buffer, along with brightness corrections
	if( redCh > 0 ){
		LEDColours[led][0] = gammaMap[redCh] + REDLEDSHIFT;
	} else {
		LEDColours[led][0] = gammaMap[redCh];
	}

	if( greenCh > 0 ){
		LEDColours[led][1] = gammaMap[greenCh] + GREENLEDSHIFT;
	} else {
		LEDColours[led][1] = gammaMap[greenCh];
	}

	if( blueCh > 0 ){
		LEDColours[led][2] = gammaMap[blueCh] + BLUELEDSHIFT;
	} else {
		LEDColours[led][2] = gammaMap[blueCh];
	}

	LEDColours[led][2] = gammaMap[blueCh];
	LEDColours[led][3] = gammaMap[dimmerCh]*4;

}

/*
	My own implementation of shift register communicaiton
		There is probably already 100's of examples of this code availble,
		but I wanted to learn...
*/
void shiftout(uint32_t input){

	//PORTD |= _BV(PORTD4); //OE high, Disable output
	PORTD &= ~(_BV(PORTD3)); //RCLK low

	for(uint8_t bit=0; bit<32; bit++){

		PORTD &= ~(_BV(PORTD1)); //SRCLK Low

		PORTD &= ~(_BV(PORTD0)); //Discards old value
		PORTD |= ((input & 1)<<PORTD0);
		input = input>>1; //Discard leftmost bit

		PORTD |= _BV(PORTD1); //SRCLK Rising edge, reading data into registry

	}

	PORTD |= _BV(PORTD3); //RCLK rising edge, loading new values in
	//PORTD &= ~(_BV(PORTD4)); //OE low, Enable output

}

/*
	LED refresh timout:
		When Timer2 overflows, or reaches the half-way point, the display should be updated.

*/
ISR(TIMER2_OVF_vect){

	//TEMP - currently using display as indicator instead. Uncomment below.
	refreshDisplay();
	PORTC ^= _BV(PORTC5); //toggle indicator

}

ISR(TIMER2_COMPB_vect, ISR_ALIASOF(TIMER2_OVF_vect));

redpajama_set_name: RedPajamaGithub


text:
package com.example.tests;

import org.testng.annotations.Test;
import static org.testng.Assert.*;
import org.testng.annotations.Test;

public class SignupTest extends TestBase {
	@Test
	public void newUserShouldSignuptest() {
		User user = new User().setLogin("testuser111").setPassword("123456")
				.setEmail("testuser11@localhost.localdomain");

		app.getAccountHelper().signUp(user);

		assertTrue(app.getAccountHelper().isLogged(user));
	}
}


text:
<?php

namespace Magento\Payment\Test\Unit\Model\Cart\SalesModel;

class QuoteTest extends \PHPUnit_Framework_TestCase
{
    /** @var \Magento\Payment\Model\Cart\SalesModel\Quote */
    protected $_model;

    /** @var \Magento\Quote\Model\Quote|\PHPUnit_Framework_MockObject_MockObject */
    protected $_quoteMock;

    protected function setUp()
    {
        $this->_quoteMock = $this->getMock('Magento\Quote\Model\Quote', [], [], '', false);
        $this->_model = new \Magento\Payment\Model\Cart\SalesModel\Quote($this->_quoteMock);
    }

    public function testGetDataUsingMethod()
    {
        $this->_quoteMock->expects(
            $this->once()
        )->method(
            'getDataUsingMethod'
        )->with(
            'any key',
            'any args'
        )->will(
            $this->returnValue('some value')
        );
        $this->assertEquals('some value', $this->_model->getDataUsingMethod('any key', 'any args'));
    }

    public function testGetTaxContainer()
    {
        $this->_quoteMock->expects(
            $this->any()
        )->method(
            'getBillingAddress'
        )->will(
            $this->returnValue('billing address')
        );
        $this->_quoteMock->expects(
            $this->any()
        )->method(
            'getShippingAddress'
        )->will(
            $this->returnValue('shipping address')
        );
        $this->assertEquals('shipping address', $this->_model->getTaxContainer());
        $this->_quoteMock->expects($this->any())->method('getIsVirtual')->will($this->returnValue(1));
        $this->assertEquals('billing address', $this->_model->getTaxContainer());
    }

    /**
     * @param string $pItem
     * @param string $name
     * @param int $qty
     * @param float $price
     * @dataProvider getAllItemsDataProvider
     */
    public function testGetAllItems($pItem, $name, $qty, $price)
    {
        $itemMock = $this->getMock('Magento\Quote\Model\Quote\Item\AbstractItem', [], [], '', false);
        $itemMock->expects($this->any())->method('getParentItem')->will($this->returnValue($pItem));
        $itemMock->expects($this->once())->method('__call')->with('getName')->will($this->returnValue($name));
        $itemMock->expects($this->any())->method('getTotalQty')->will($this->returnValue($qty));
        $itemMock->expects($this->any())->method('getBaseCalculationPrice')->will($this->returnValue($price));
        $expected = [
            new \Magento\Framework\DataObject(
                [
                    'parent_item' => $pItem,
                    'name' => $name,
                    'qty' => $qty,
                    'price' => $price,
                    'original_item' => $itemMock,
                ]
            ),
        ];
        $this->_quoteMock->expects($this->once())->method('getAllItems')->will($this->returnValue([$itemMock]));
        $this->assertEquals($expected, $this->_model->getAllItems());
    }

    public function getAllItemsDataProvider()
    {
        return [
            ['parent item 1', 'name 1', 1, 0.1],
            ['parent item 2', 'name 2', 2, 1.2],
            ['parent item 3', 'name 3', 3, 2.3],
        ];
    }

    public function testGetBaseSubtotal()
    {
        $this->_quoteMock->expects(
            $this->once()
        )->method(
            '__call'
        )->with(
            'getBaseSubtotal'
        )->will(
            $this->returnValue(100)
        );
        $this->assertEquals(100, $this->_model->getBaseSubtotal());
    }

    /**
     * @param int $isVirtual
     * @param string $getterMethod
     * @dataProvider getterDataProvider
     */
    public function testGetter($isVirtual, $getterMethod)
    {
        $address = $this->getMock('Magento\Quote\Model\Quote\Address', [], [], '', false);
        $address->expects(
            $this->any()
        )->method(
            '__call'
        )->with(
            $getterMethod
        )->will(
            $this->returnValue($getterMethod)
        );
        $quoteMock = $this->getMock('Magento\Quote\Model\Quote', [], [], '', false);
        $quoteMock->expects($this->any())->method('getIsVirtual')->will($this->returnValue($isVirtual));
        $method = 'getShippingAddress';
        if ($isVirtual) {
            $method = 'getBillingAddress';
        }
        $quoteMock->expects($this->any())->method($method)->will($this->returnValue($address));
        $model = new \Magento\Payment\Model\Cart\SalesModel\Quote($quoteMock);
        $this->assertEquals($getterMethod, $model->{$getterMethod}());
    }

    public function getterDataProvider()
    {
        return [
            [0, 'getBaseTaxAmount'],
            [1, 'getBaseTaxAmount'],
            [0, 'getBaseShippingAmount'],
            [1, 'getBaseShippingAmount'],
            [0, 'getBaseDiscountAmount'],
            [1, 'getBaseDiscountAmount']
        ];
    }
}


text:
@implementation KSHelper

////////////////////////////////////////////////////////////////////////////////

#pragma mark - Device

+ (BOOL)isPad
{
    return ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad);
}

+ (BOOL)isPhone
{
    return ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone);

}

+ (NSString *)device
{
    if ([self isPhone]) return @"iPhone";
    if ([self isPad]) return @"iPad";
    abort();
}

@end


text:
namespace swift {

struct MouseEvent {

  enum class Type {
    MOVE, SCROLL, PRESS, RELEASE
  };

  //////////////////////////////////////////////////////////////////////////////
  // ---------------------------------------------------------- public interface
  MouseEvent()
  : type_(Type::MOVE)
  , x_(0)
  , y_(0)
  {}

  // either MOVE, SCROLL, PRESS or RELEASE
  Type type_;

  union {
    // x-position for MOVE, x-direction for SCROLL
    int    x_;

    // only used for PRESS and RELEASE
    Button button_;
  };

  // y-position for MOVE, y-direction for SCROLL
  int y_;
};

}

#endif // SWIFT_MOUSE_EVENT_HPP


text:
using System;
using System.Collections.Generic;
using System.Linq;

namespace Azure.Management.Network.Models
{
    /// <summary> Describes the connection monitor test group. </summary>
    public partial class ConnectionMonitorTestGroup
    {
        /// <summary> Initializes a new instance of ConnectionMonitorTestGroup. </summary>
        /// <param name="name"> The name of the connection monitor test group. </param>
        /// <param name="testConfigurations"> List of test configuration names. </param>
        /// <param name="sources"> List of source endpoint names. </param>
        /// <param name="destinations"> List of destination endpoint names. </param>
        public ConnectionMonitorTestGroup(string name, IEnumerable<string> testConfigurations, IEnumerable<string> sources, IEnumerable<string> destinations)
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }
            if (testConfigurations == null)
            {
                throw new ArgumentNullException(nameof(testConfigurations));
            }
            if (sources == null)
            {
                throw new ArgumentNullException(nameof(sources));
            }
            if (destinations == null)
            {
                throw new ArgumentNullException(nameof(destinations));
            }

            Name = name;
            TestConfigurations = testConfigurations.ToArray();
            Sources = sources.ToArray();
            Destinations = destinations.ToArray();
        }

        /// <summary> Initializes a new instance of ConnectionMonitorTestGroup. </summary>
        /// <param name="name"> The name of the connection monitor test group. </param>
        /// <param name="disable"> Value indicating whether test group is disabled. </param>
        /// <param name="testConfigurations"> List of test configuration names. </param>
        /// <param name="sources"> List of source endpoint names. </param>
        /// <param name="destinations"> List of destination endpoint names. </param>
        internal ConnectionMonitorTestGroup(string name, bool? disable, IList<string> testConfigurations, IList<string> sources, IList<string> destinations)
        {
            Name = name;
            Disable = disable;
            TestConfigurations = testConfigurations;
            Sources = sources;
            Destinations = destinations;
        }

        /// <summary> The name of the connection monitor test group. </summary>
        public string Name { get; set; }
        /// <summary> Value indicating whether test group is disabled. </summary>
        public bool? Disable { get; set; }
        /// <summary> List of test configuration names. </summary>
        public IList<string> TestConfigurations { get; set; }
        /// <summary> List of source endpoint names. </summary>
        public IList<string> Sources { get; set; }
        /// <summary> List of destination endpoint names. </summary>
        public IList<string> Destinations { get; set; }
    }
}


text:
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=2 et tw=78: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/**
 * This file is near-OBSOLETE. It is used for about:blank only and for the
 * HTML element factory.
 * Don't bother adding new stuff in this file.
 */

#include "mozilla/Util.h"

#include "nsContentSink.h"
#include "nsCOMPtr.h"
#include "nsReadableUtils.h"
#include "nsUnicharUtils.h"
#include "nsIHTMLContentSink.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsScriptLoader.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
#include "nsIContentViewer.h"
#include "nsIMarkupDocumentViewer.h"
#include "nsINodeInfo.h"
#include "nsHTMLTokens.h"
#include "nsIAppShell.h"
#include "nsCRT.h"
#include "prtime.h"
#include "prlog.h"
#include "nsNodeUtils.h"
#include "nsIContent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/Preferences.h"

#include "nsGenericHTMLElement.h"

#include "nsIDOMDocument.h"
#include "nsIDOMDocumentType.h"
#include "nsIScriptElement.h"

#include "nsIComponentManager.h"
#include "nsIServiceManager.h"

#include "nsGkAtoms.h"
#include "nsContentUtils.h"
#include "nsIChannel.h"
#include "nsIHttpChannel.h"
#include "nsIDocShell.h"
#include "nsIDocument.h"
#include "nsStubDocumentObserver.h"
#include "nsIHTMLDocument.h"
#include "nsINameSpaceManager.h"
#include "nsIDOMHTMLMapElement.h"
#include "nsICookieService.h"
#include "nsTArray.h"
#include "nsIScriptSecurityManager.h"
#include "nsIPrincipal.h"
#include "nsTextFragment.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptGlobalObjectOwner.h"

#include "nsIParserService.h"

#include "nsIStyleSheetLinkingElement.h"
#include "nsITimer.h"
#include "nsError.h"
#include "nsContentPolicyUtils.h"
#include "nsIScriptContext.h"
#include "nsStyleLinkElement.h"

#include "nsWeakReference.h" // nsHTMLElementFactory supports weak references
#include "nsIPrompt.h"
#include "nsLayoutCID.h"
#include "nsIDocShellTreeItem.h"

#include "nsEscape.h"
#include "nsIElementObserver.h"
#include "nsNodeInfoManager.h"
#include "nsContentCreatorFunctions.h"
#include "mozAutoDocUpdate.h"

using namespace mozilla;
using namespace mozilla::dom;

#ifdef DEBUG
static PRLogModuleInfo* gSinkLogModuleInfo;

#define SINK_TRACE_NODE(_bit, _msg, _tag, _sp, _obj) \
  _obj->SinkTraceNode(_bit, _msg, _tag, _sp, this)

#else
#define SINK_TRACE_NODE(_bit, _msg, _tag, _sp, _obj)
#endif

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

typedef nsGenericHTMLElement*
  (*contentCreatorCallback)(already_AddRefed<nsINodeInfo>,
                            FromParser aFromParser);

nsGenericHTMLElement*
NS_NewHTMLNOTUSEDElement(already_AddRefed<nsINodeInfo> aNodeInfo,
                         FromParser aFromParser)
{
  NS_NOTREACHED("The element ctor should never be called");
  return nullptr;
}

#define HTML_TAG(_tag, _classname) NS_NewHTML##_classname##Element,
#define HTML_HTMLELEMENT_TAG(_tag) NS_NewHTMLElement,
#define HTML_OTHER(_tag) NS_NewHTMLNOTUSEDElement,
static const contentCreatorCallback sContentCreatorCallbacks[] = {
  NS_NewHTMLUnknownElement,
#include "nsHTMLTagList.h"
#undef HTML_TAG
#undef HTML_HTMLELEMENT_TAG
#undef HTML_OTHER
  NS_NewHTMLUnknownElement
};

class SinkContext;
class HTMLContentSink;

/**
 * This class is near-OBSOLETE. It is used for about:blank only.
 * Don't bother adding new stuff in this file.
 */
class HTMLContentSink : public nsContentSink,
#ifdef DEBUG
                        public nsIDebugDumpContent,
#endif
                        public nsIHTMLContentSink
{
public:
  friend class SinkContext;

  HTMLContentSink();
  virtual ~HTMLContentSink();

  NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW

  nsresult Init(nsIDocument* aDoc, nsIURI* aURI, nsISupports* aContainer,
                nsIChannel* aChannel);

  // nsISupports
  NS_DECL_ISUPPORTS_INHERITED
  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLContentSink, nsContentSink)

  // nsIContentSink
  NS_IMETHOD WillParse(void);
  NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode);
  NS_IMETHOD DidBuildModel(bool aTerminated);
  NS_IMETHOD WillInterrupt(void);
  NS_IMETHOD WillResume(void);
  NS_IMETHOD SetParser(nsParserBase* aParser);
  virtual void FlushPendingNotifications(mozFlushType aType);
  NS_IMETHOD SetDocumentCharset(nsACString& aCharset);
  virtual nsISupports *GetTarget();
  virtual bool IsScriptExecuting();

  // nsIHTMLContentSink
  NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
  NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
  NS_IMETHOD CloseMalformedContainer(const nsHTMLTag aTag);
  NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
  NS_IMETHOD DidProcessTokens(void);
  NS_IMETHOD WillProcessAToken(void);
  NS_IMETHOD DidProcessAToken(void);
  NS_IMETHOD BeginContext(int32_t aID);
  NS_IMETHOD EndContext(int32_t aID);
  NS_IMETHOD OpenHead();
  NS_IMETHOD IsEnabled(int32_t aTag, bool* aReturn);

#ifdef DEBUG
  // nsIDebugDumpContent
  NS_IMETHOD DumpContentModel();
#endif

protected:
  // If aCheckIfPresent is true, will only set an attribute in cases
  // when it's not already set.
  nsresult AddAttributes(const nsIParserNode& aNode, nsIContent* aContent,
                         bool aNotify = false,
                         bool aCheckIfPresent = false);
  already_AddRefed<nsGenericHTMLElement>
  CreateContentObject(const nsIParserNode& aNode, nsHTMLTag aNodeType);

#ifdef DEBUG
  void SinkTraceNode(uint32_t aBit,
                     const char* aMsg,
                     const nsHTMLTag aTag,
                     int32_t aStackPos,
                     void* aThis);
#endif

  nsCOMPtr<nsIHTMLDocument> mHTMLDocument;

  // The maximum length of a text run
  int32_t mMaxTextRun;

  nsRefPtr<nsGenericHTMLElement> mRoot;
  nsRefPtr<nsGenericHTMLElement> mBody;
  nsRefPtr<nsGenericHTMLElement> mHead;

  nsAutoTArray<SinkContext*, 8> mContextStack;
  SinkContext* mCurrentContext;
  SinkContext* mHeadContext;

  // Boolean indicating whether we've seen a <head> tag that might have had
  // attributes once already.
  bool mHaveSeenHead;

  // Boolean indicating whether we've notified insertion of our root content
  // yet.  We want to make sure to only do this once.
  bool mNotifiedRootInsertion;

  uint8_t mScriptEnabled : 1;
  uint8_t mFramesEnabled : 1;
  uint8_t unused : 6;  // bits available if someone needs one

  nsINodeInfo* mNodeInfoCache[NS_HTML_TAG_MAX + 1];

  nsresult FlushTags();

  // Routines for tags that require special handling
  nsresult CloseHTML();
  nsresult OpenBody(const nsIParserNode& aNode);
  nsresult CloseBody();

  nsresult OpenHeadContext();
  void CloseHeadContext();

  // nsContentSink overrides
  void UpdateChildCounts();

  void NotifyInsert(nsIContent* aContent,
                    nsIContent* aChildContent,
                    int32_t aIndexInContainer);
  void NotifyRootInsertion();

  bool IsMonolithicContainer(nsHTMLTag aTag);

#ifdef DEBUG
  void ForceReflow();
#endif
};

class SinkContext
{
public:
  SinkContext(HTMLContentSink* aSink);
  ~SinkContext();

  nsresult Begin(nsHTMLTag aNodeType, nsGenericHTMLElement* aRoot,
                 uint32_t aNumFlushed, int32_t aInsertionPoint);
  nsresult OpenContainer(const nsIParserNode& aNode);
  nsresult CloseContainer(const nsHTMLTag aTag);
  nsresult AddLeaf(const nsIParserNode& aNode);
  nsresult AddLeaf(nsIContent* aContent);
  nsresult End();

  nsresult GrowStack();
  nsresult AddText(const nsAString& aText);
  nsresult FlushText(bool* aDidFlush = nullptr,
                     bool aReleaseLast = false);
  nsresult FlushTextAndRelease(bool* aDidFlush = nullptr)
  {
    return FlushText(aDidFlush, true);
  }

  nsresult FlushTags();

  bool     IsCurrentContainer(nsHTMLTag mType);

  void DidAddContent(nsIContent* aContent);
  void UpdateChildCounts();

private:
  // Function to check whether we've notified for the current content.
  // What this actually does is check whether we've notified for all
  // of the parent's kids.
  bool HaveNotifiedForCurrentContent() const;

public:
  HTMLContentSink* mSink;
  int32_t mNotifyLevel;
  nsCOMPtr<nsIContent> mLastTextNode;
  int32_t mLastTextNodeSize;

  struct Node {
    nsHTMLTag mType;
    nsGenericHTMLElement* mContent;
    uint32_t mNumFlushed;
    int32_t mInsertionPoint;

    nsIContent *Add(nsIContent *child);
  };

  Node* mStack;
  int32_t mStackSize;
  int32_t mStackPos;

  PRUnichar* mText;
  int32_t mTextLength;
  int32_t mTextSize;

private:
  bool mLastTextCharWasCR;
};

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

#ifdef DEBUG
void
HTMLContentSink::SinkTraceNode(uint32_t aBit,
                               const char* aMsg,
                               const nsHTMLTag aTag,
                               int32_t aStackPos,
                               void* aThis)
{
  if (SINK_LOG_TEST(gSinkLogModuleInfo, aBit)) {
    nsIParserService *parserService = nsContentUtils::GetParserService();
    if (!parserService)
      return;

    NS_ConvertUTF16toUTF8 tag(parserService->HTMLIdToStringTag(aTag));
    PR_LogPrint("%s: this=%p node='%s' stackPos=%d",
                aMsg, aThis, tag.get(), aStackPos);
  }
}
#endif

nsresult
HTMLContentSink::AddAttributes(const nsIParserNode& aNode,
                               nsIContent* aContent, bool aNotify,
                               bool aCheckIfPresent)
{
  // Add tag attributes to the content attributes

  int32_t ac = aNode.GetAttributeCount();

  if (ac == 0) {
    // No attributes, nothing to do. Do an early return to avoid
    // constructing the nsAutoString object for nothing.

    return NS_OK;
  }

  nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());

  // The attributes are on the parser node in the order they came in in the
  // source.  What we want to happen if a single attribute is set multiple
  // times on an element is that the first time should "win".  That is, <input
  // value="foo" value="bar"> should show "foo".  So we loop over the
  // attributes backwards; this ensures that the first attribute in the set
  // wins.  This does mean that we do some extra work in the case when the same
  // attribute is set multiple times, but we save a HasAttr call in the much
  // more common case of reasonable HTML.  Note that if aCheckIfPresent is set
  // then we actually want to loop _forwards_ to preserve the "first attribute
  // wins" behavior.  That does mean that when aCheckIfPresent is set the order
  // of attributes will get "reversed" from the point of view of the
  // serializer.  But aCheckIfPresent is only true for malformed documents with
  // multiple <html>, <head>, or <body> tags, so we're doing fixup anyway at
  // that point.

  int32_t i, limit, step;
  if (aCheckIfPresent) {
    i = 0;
    limit = ac;
    step = 1;
  } else {
    i = ac - 1;
    limit = -1;
    step = -1;
  }

  nsAutoString key;
  for (; i != limit; i += step) {
    // Get lower-cased key
    nsresult rv = nsContentUtils::ASCIIToLower(aNode.GetKeyAt(i), key);
    if (NS_FAILED(rv)) {
      return rv;
    }

    nsCOMPtr<nsIAtom> keyAtom = do_GetAtom(key);

    if (aCheckIfPresent && aContent->HasAttr(kNameSpaceID_None, keyAtom)) {
      continue;
    }

    // Get value and remove mandatory quotes
    static const char* kWhitespace = "\n\r\t\b";

    // Bug 114997: Don't trim whitespace on <input value="...">:
    // Using ?: outside the function call would be more efficient, but
    // we don't trust ?: with references.
    const nsAString& v =
      nsContentUtils::TrimCharsInSet(
        (nodeType == eHTMLTag_input &&
          keyAtom == nsGkAtoms::value) ?
        "" : kWhitespace, aNode.GetValueAt(i));

    if (nodeType == eHTMLTag_a && keyAtom == nsGkAtoms::name) {
      NS_ConvertUTF16toUTF8 cname(v);
      NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting()));

      // Add attribute to content
      aContent->SetAttr(kNameSpaceID_None, keyAtom, uv, aNotify);
    } else {
      // Add attribute to content
      aContent->SetAttr(kNameSpaceID_None, keyAtom, v, aNotify);
    }
  }

  return NS_OK;
}

/**
 * Factory subroutine to create all of the html content objects.
 */
already_AddRefed<nsGenericHTMLElement>
HTMLContentSink::CreateContentObject(const nsIParserNode& aNode,
                                     nsHTMLTag aNodeType)
{
  // Find/create atom for the tag name

  nsCOMPtr<nsINodeInfo> nodeInfo;

  if (aNodeType == eHTMLTag_userdefined) {
    nsAutoString lower;
    nsContentUtils::ASCIIToLower(aNode.GetText(), lower);
    nsCOMPtr<nsIAtom> name = do_GetAtom(lower);
    nodeInfo = mNodeInfoManager->GetNodeInfo(name, nullptr, kNameSpaceID_XHTML,
                                             nsIDOMNode::ELEMENT_NODE);
  }
  else if (mNodeInfoCache[aNodeType]) {
    nodeInfo = mNodeInfoCache[aNodeType];
  }
  else {
    nsIParserService *parserService = nsContentUtils::GetParserService();
    if (!parserService)
      return nullptr;

    nsIAtom *name = parserService->HTMLIdToAtomTag(aNodeType);
    NS_ASSERTION(name, "What? Reverse mapping of id to string broken!!!");

    nodeInfo = mNodeInfoManager->GetNodeInfo(name, nullptr, kNameSpaceID_XHTML,
                                             nsIDOMNode::ELEMENT_NODE);
    NS_IF_ADDREF(mNodeInfoCache[aNodeType] = nodeInfo);
  }

  NS_ENSURE_TRUE(nodeInfo, nullptr);

  // Make the content object
  return CreateHTMLElement(aNodeType, nodeInfo.forget(), FROM_PARSER_NETWORK);
}

nsresult
NS_NewHTMLElement(nsIContent** aResult, already_AddRefed<nsINodeInfo> aNodeInfo,
                  FromParser aFromParser)
{
  *aResult = nullptr;

  nsCOMPtr<nsINodeInfo> nodeInfo = aNodeInfo;

  nsIParserService* parserService = nsContentUtils::GetParserService();
  if (!parserService)
    return NS_ERROR_OUT_OF_MEMORY;

  nsIAtom *name = nodeInfo->NameAtom();

  NS_ASSERTION(nodeInfo->NamespaceEquals(kNameSpaceID_XHTML),
               "Trying to HTML elements that don't have the XHTML namespace");

  *aResult = CreateHTMLElement(parserService->
                                 HTMLCaseSensitiveAtomTagToId(name),
                               nodeInfo.forget(), aFromParser).get();
  return *aResult ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}

already_AddRefed<nsGenericHTMLElement>
CreateHTMLElement(uint32_t aNodeType, already_AddRefed<nsINodeInfo> aNodeInfo,
                  FromParser aFromParser)
{
  NS_ASSERTION(aNodeType <= NS_HTML_TAG_MAX ||
               aNodeType == eHTMLTag_userdefined,
               "aNodeType is out of bounds");

  contentCreatorCallback cb = sContentCreatorCallbacks[aNodeType];

  NS_ASSERTION(cb != NS_NewHTMLNOTUSEDElement,
               "Don't know how to construct tag element!");

  nsGenericHTMLElement* result = cb(aNodeInfo, aFromParser);
  NS_IF_ADDREF(result);

  return result;
}

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

SinkContext::SinkContext(HTMLContentSink* aSink)
  : mSink(aSink),
    mNotifyLevel(0),
    mLastTextNodeSize(0),
    mStack(nullptr),
    mStackSize(0),
    mStackPos(0),
    mText(nullptr),
    mTextLength(0),
    mTextSize(0),
    mLastTextCharWasCR(false)
{
  MOZ_COUNT_CTOR(SinkContext);
}

SinkContext::~SinkContext()
{
  MOZ_COUNT_DTOR(SinkContext);

  if (mStack) {
    for (int32_t i = 0; i < mStackPos; i++) {
      NS_RELEASE(mStack[i].mContent);
    }
    delete [] mStack;
  }

  delete [] mText;
}

nsresult
SinkContext::Begin(nsHTMLTag aNodeType,
                   nsGenericHTMLElement* aRoot,
                   uint32_t aNumFlushed,
                   int32_t aInsertionPoint)
{
  if (mStackSize < 1) {
    nsresult rv = GrowStack();
    if (NS_FAILED(rv)) {
      return rv;
    }
  }

  mStack[0].mType = aNodeType;
  mStack[0].mContent = aRoot;
  mStack[0].mNumFlushed = aNumFlushed;
  mStack[0].mInsertionPoint = aInsertionPoint;
  NS_ADDREF(aRoot);
  mStackPos = 1;
  mTextLength = 0;

  return NS_OK;
}

bool
SinkContext::IsCurrentContainer(nsHTMLTag aTag)
{
  if (aTag == mStack[mStackPos - 1].mType) {
    return true;
  }

  return false;
}

void
SinkContext::DidAddContent(nsIContent* aContent)
{
  if ((mStackPos == 2) && (mSink->mBody == mStack[1].mContent)) {
    // We just finished adding something to the body
    mNotifyLevel = 0;
  }

  // If we just added content to a node for which
  // an insertion happen, we need to do an immediate
  // notification for that insertion.
  if (0 < mStackPos &&
      mStack[mStackPos - 1].mInsertionPoint != -1 &&
      mStack[mStackPos - 1].mNumFlushed <
      mStack[mStackPos - 1].mContent->GetChildCount()) {
    nsIContent* parent = mStack[mStackPos - 1].mContent;

#ifdef DEBUG
    // Tracing code
    nsIParserService *parserService = nsContentUtils::GetParserService();
    if (parserService) {
      nsHTMLTag tag = nsHTMLTag(mStack[mStackPos - 1].mType);
      NS_ConvertUTF16toUTF8 str(parserService->HTMLIdToStringTag(tag));

      SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
                 ("SinkContext::DidAddContent: Insertion notification for "
                  "parent=%s at position=%d and stackPos=%d",
                  str.get(), mStack[mStackPos - 1].mInsertionPoint - 1,
                  mStackPos - 1));
    }
#endif

    int32_t childIndex = mStack[mStackPos - 1].mInsertionPoint - 1;
    NS_ASSERTION(parent->GetChildAt(childIndex) == aContent,
                 "Flushing the wrong child.");
    mSink->NotifyInsert(parent, aContent, childIndex);
    mStack[mStackPos - 1].mNumFlushed = parent->GetChildCount();
  } else if (mSink->IsTimeToNotify()) {
    SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
               ("SinkContext::DidAddContent: Notification as a result of the "
                "interval expiring; backoff count: %d", mSink->mBackoffCount));
    FlushTags();
  }
}

nsresult
SinkContext::OpenContainer(const nsIParserNode& aNode)
{
  FlushTextAndRelease();

  SINK_TRACE_NODE(SINK_TRACE_CALLS,
                  "SinkContext::OpenContainer",
                  nsHTMLTag(aNode.GetNodeType()),
                  mStackPos,
                  mSink);

  if (mStackPos <= 0) {
    NS_ERROR("container w/o parent");

    return NS_ERROR_FAILURE;
  }

  nsresult rv;
  if (mStackPos + 1 > mStackSize) {
    rv = GrowStack();
    if (NS_FAILED(rv)) {
      return rv;
    }
  }

  // Create new container content object
  nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());
  nsGenericHTMLElement* content =
    mSink->CreateContentObject(aNode, nodeType).get();
  if (!content) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  mStack[mStackPos].mType = nodeType;
  mStack[mStackPos].mContent = content;
  mStack[mStackPos].mNumFlushed = 0;
  mStack[mStackPos].mInsertionPoint = -1;
  ++mStackPos;

  rv = mSink->AddAttributes(aNode, content);

  mStack[mStackPos - 2].Add(content);

  NS_ENSURE_SUCCESS(rv, rv);

  if (mSink->IsMonolithicContainer(nodeType)) {
    mSink->mInMonolithicContainer++;
  }

  // Special handling for certain tags
  switch (nodeType) {
    case eHTMLTag_form:
      MOZ_NOT_REACHED("Must not use HTMLContentSink for forms.");
      break;

    case eHTMLTag_frameset:
      MOZ_NOT_REACHED("Must not use HTMLContentSink for frames.");
      break;

    case eHTMLTag_noembed:
    case eHTMLTag_noframes:
      MOZ_NOT_REACHED("Must not use HTMLContentSink for noembed/noframes.");
      break;

    case eHTMLTag_script:
    case eHTMLTag_style:
      MOZ_NOT_REACHED("Must not use HTMLContentSink for styles and scripts.");
      break;

    case eHTMLTag_button:
#ifdef MOZ_MEDIA
    case eHTMLTag_audio:
    case eHTMLTag_video:
#endif
      content->DoneCreatingElement();
      break;

    default:
      break;
  }

  return NS_OK;
}

bool
SinkContext::HaveNotifiedForCurrentContent() const
{
  if (0 < mStackPos) {
    nsIContent* parent = mStack[mStackPos - 1].mContent;
    return mStack[mStackPos-1].mNumFlushed == parent->GetChildCount();
  }

  return true;
}

nsIContent *
SinkContext::Node::Add(nsIContent *child)
{
  NS_ASSERTION(mContent, "No parent to insert/append into!");
  if (mInsertionPoint != -1) {
    NS_ASSERTION(mNumFlushed == mContent->GetChildCount(),
                 "Inserting multiple children without flushing.");
    mContent->InsertChildAt(child, mInsertionPoint++, false);
  } else {
    mContent->AppendChildTo(child, false);
  }
  return child;
}

nsresult
SinkContext::CloseContainer(const nsHTMLTag aTag)
{
  nsresult result = NS_OK;

  // Flush any collected text content. Release the last text
  // node to indicate that no more should be added to it.
  FlushTextAndRelease();

  SINK_TRACE_NODE(SINK_TRACE_CALLS,
                  "SinkContext::CloseContainer",
                  aTag, mStackPos - 1, mSink);

  NS_ASSERTION(mStackPos > 0,
               "stack out of bounds. wrong context probably!");

  if (mStackPos <= 0) {
    return NS_OK; // Fix crash - Ref. bug 45975 or 45007
  }

  --mStackPos;
  nsHTMLTag nodeType = mStack[mStackPos].mType;

  NS_ASSERTION(nodeType == aTag,
               "Tag mismatch.  Closing tag on wrong context or something?");

  nsGenericHTMLElement* content = mStack[mStackPos].mContent;

  content->Compact();

  // If we're in a state where we do append notifications as
  // we go up the tree, and we're at the level where the next
  // notification needs to be done, do the notification.
  if (mNotifyLevel >= mStackPos) {
    // Check to see if new content has been added after our last
    // notification

    if (mStack[mStackPos].mNumFlushed < content->GetChildCount()) {
#ifdef DEBUG
      {
        // Tracing code
        SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
                   ("SinkContext::CloseContainer: reflow on notifyImmediate "
                    "tag=%s newIndex=%d stackPos=%d",
                    nsAtomCString(mStack[mStackPos].mContent->Tag()).get(),
                    mStack[mStackPos].mNumFlushed, mStackPos));
      }
#endif
      mSink->NotifyAppend(content, mStack[mStackPos].mNumFlushed);
      mStack[mStackPos].mNumFlushed = content->GetChildCount();
    }

    // Indicate that notification has now happened at this level
    mNotifyLevel = mStackPos - 1;
  }

  if (mSink->IsMonolithicContainer(nodeType)) {
    --mSink->mInMonolithicContainer;
  }

  DidAddContent(content);

  // Special handling for certain tags
  switch (nodeType) {
  case eHTMLTag_noembed:
  case eHTMLTag_noframes:
    MOZ_NOT_REACHED("Must not use HTMLContentSink for noembed/noframes.");
    break;

  case eHTMLTag_form:
    MOZ_NOT_REACHED("Must not use HTMLContentSink for forms.");
    break;

#ifdef MOZ_MEDIA
  case eHTMLTag_video:
  case eHTMLTag_audio:
#endif
  case eHTMLTag_select:
  case eHTMLTag_textarea:
  case eHTMLTag_object:
  case eHTMLTag_applet:
  case eHTMLTag_title:
    content->DoneAddingChildren(HaveNotifiedForCurrentContent());
    break;

  case eHTMLTag_script:
    MOZ_NOT_REACHED("Must not use HTMLContentSink to run scripts.");
    result = NS_ERROR_NOT_IMPLEMENTED;
    break;

  case eHTMLTag_style:
    MOZ_NOT_REACHED("Must not use HTMLContentSink for styles.");
    result = NS_ERROR_NOT_IMPLEMENTED;
    break;

  default:
    break;
  }

  NS_IF_RELEASE(content);

#ifdef DEBUG
  if (SINK_LOG_TEST(gSinkLogModuleInfo, SINK_ALWAYS_REFLOW)) {
    mSink->ForceReflow();
  }
#endif

  return result;
}

nsresult
SinkContext::AddLeaf(const nsIParserNode& aNode)
{
  SINK_TRACE_NODE(SINK_TRACE_CALLS,
                  "SinkContext::AddLeaf",
                  nsHTMLTag(aNode.GetNodeType()),
                  mStackPos, mSink);

  nsresult rv = NS_OK;

  switch (aNode.GetTokenType()) {
  case eToken_start:
    {
      FlushTextAndRelease();

      // Create new leaf content object
      nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());
      nsRefPtr<nsGenericHTMLElement> content =
        mSink->CreateContentObject(aNode, nodeType);
      NS_ENSURE_TRUE(content, NS_ERROR_OUT_OF_MEMORY);

      rv = mSink->AddAttributes(aNode, content);
      NS_ENSURE_SUCCESS(rv, rv);

      // Add new leaf to its parent
      AddLeaf(content);

      // Additional processing needed once the element is in the tree
      switch (nodeType) {
      case eHTMLTag_meta:
        MOZ_NOT_REACHED("Must not use HTMLContentSink for metas.");
        rv = NS_ERROR_NOT_IMPLEMENTED;
        break;

      case eHTMLTag_input:
        content->DoneCreatingElement();
        break;

      case eHTMLTag_menuitem:
        content->DoneCreatingElement();
        break;

      default:
        break;
      }
    }
    break;

  case eToken_text:
  case eToken_whitespace:
  case eToken_newline:
    rv = AddText(aNode.GetText());

    break;
  case eToken_entity:
    {
      nsAutoString tmp;
      int32_t unicode = aNode.TranslateToUnicodeStr(tmp);
      if (unicode < 0) {
        rv = AddText(aNode.GetText());
      } else {
        // Map carriage returns to newlines
        if (!tmp.IsEmpty()) {
          if (tmp.CharAt(0) == '\r') {
            tmp.Assign((PRUnichar)'\n');
          }
          rv = AddText(tmp);
        }
      }
    }

    break;
  default:
    break;
  }

  return rv;
}

nsresult
SinkContext::AddLeaf(nsIContent* aContent)
{
  NS_ASSERTION(mStackPos > 0, "leaf w/o container");
  if (mStackPos <= 0) {
    return NS_ERROR_FAILURE;
  }

  DidAddContent(mStack[mStackPos - 1].Add(aContent));

#ifdef DEBUG
  if (SINK_LOG_TEST(gSinkLogModuleInfo, SINK_ALWAYS_REFLOW)) {
    mSink->ForceReflow();
  }
#endif

  return NS_OK;
}

nsresult
SinkContext::End()
{
  for (int32_t i = 0; i < mStackPos; i++) {
    NS_RELEASE(mStack[i].mContent);
  }

  mStackPos = 0;
  mTextLength = 0;

  return NS_OK;
}

nsresult
SinkContext::GrowStack()
{
  int32_t newSize = mStackSize * 2;
  if (newSize == 0) {
    newSize = 32;
  }

  Node* stack = new Node[newSize];
  if (!stack) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  if (mStackPos != 0) {
    memcpy(stack, mStack, sizeof(Node) * mStackPos);
    delete [] mStack;
  }

  mStack = stack;
  mStackSize = newSize;

  return NS_OK;
}

/**
 * Add textual content to the current running text buffer. If the text buffer
 * overflows, flush out the text by creating a text content object and adding
 * it to the content tree.
 */

// XXX If we get a giant string grow the buffer instead of chopping it
// up???
nsresult
SinkContext::AddText(const nsAString& aText)
{
  int32_t addLen = aText.Length();
  if (addLen == 0) {
    return NS_OK;
  }

  // Create buffer when we first need it
  if (mTextSize == 0) {
    mText = new PRUnichar[4096];
    if (!mText) {
      return NS_ERROR_OUT_OF_MEMORY;
    }
    mTextSize = 4096;
  }

  // Copy data from string into our buffer; flush buffer when it fills up
  int32_t offset = 0;

  while (addLen != 0) {
    int32_t amount = mTextSize - mTextLength;

    if (amount > addLen) {
      amount = addLen;
    }

    if (amount == 0) {
      // Don't release last text node so we can add to it again
      nsresult rv = FlushText();
      if (NS_FAILED(rv)) {
        return rv;
      }

      // Go back to the top of the loop so we re-calculate amount and
      // don't fall through to CopyNewlineNormalizedUnicodeTo with a
      // zero-length amount (which invalidates mLastTextCharWasCR).
      continue;
    }

    mTextLength +=
      nsContentUtils::CopyNewlineNormalizedUnicodeTo(aText, offset,
                                                     &mText[mTextLength],
                                                     amount,
                                                     mLastTextCharWasCR);
    offset += amount;
    addLen -= amount;
  }

  return NS_OK;
}

/**
 * NOTE!! Forked into nsXMLContentSink. Please keep in sync.
 *
 * Flush all elements that have been seen so far such that
 * they are visible in the tree. Specifically, make sure
 * that they are all added to their respective parents.
 * Also, do notification at the top for all content that
 * has been newly added so that the frame tree is complete.
 */
nsresult
SinkContext::FlushTags()
{
  mSink->mDeferredFlushTags = false;
  bool oldBeganUpdate = mSink->mBeganUpdate;
  uint32_t oldUpdates = mSink->mUpdatesInNotification;

  ++(mSink->mInNotification);
  mSink->mUpdatesInNotification = 0;
  {
    // Scope so we call EndUpdate before we decrease mInNotification
    mozAutoDocUpdate updateBatch(mSink->mDocument, UPDATE_CONTENT_MODEL,
                                 true);
    mSink->mBeganUpdate = true;

    // Don't release last text node in case we need to add to it again
    FlushText();

    // Start from the base of the stack (growing downward) and do
    // a notification from the node that is closest to the root of
    // tree for any content that has been added.

    // Note that we can start at stackPos == 0 here, because it's the caller's
    // responsibility to handle flushing interactions between contexts (see
    // HTMLContentSink::BeginContext).
    int32_t stackPos = 0;
    bool flushed = false;
    uint32_t childCount;
    nsGenericHTMLElement* content;

    while (stackPos < mStackPos) {
      content = mStack[stackPos].mContent;
      childCount = content->GetChildCount();

      if (!flushed && (mStack[stackPos].mNumFlushed < childCount)) {
#ifdef DEBUG
        {
          // Tracing code
          SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
                     ("SinkContext::FlushTags: tag=%s from newindex=%d at "
                      "stackPos=%d",
                      nsAtomCString(mStack[stackPos].mContent->Tag()).get(),
                      mStack[stackPos].mNumFlushed, stackPos));
        }
#endif
        if (mStack[stackPos].mInsertionPoint != -1) {
          // We might have popped the child off our stack already
          // but not notified on it yet, which is why we have to get it
          // directly from its parent node.

          int32_t childIndex = mStack[stackPos].mInsertionPoint - 1;
          nsIContent* child = content->GetChildAt(childIndex);
          // Child not on stack anymore; can't assert it's correct
          NS_ASSERTION(!(mStackPos > (stackPos + 1)) ||
                       (child == mStack[stackPos + 1].mContent),
                       "Flushing the wrong child.");
          mSink->NotifyInsert(content, child, childIndex);
        } else {
          mSink->NotifyAppend(content, mStack[stackPos].mNumFlushed);
        }

        flushed = true;
      }

      mStack[stackPos].mNumFlushed = childCount;
      stackPos++;
    }
    mNotifyLevel = mStackPos - 1;
  }
  --(mSink->mInNotification);

  if (mSink->mUpdatesInNotification > 1) {
    UpdateChildCounts();
  }

  mSink->mUpdatesInNotification = oldUpdates;
  mSink->mBeganUpdate = oldBeganUpdate;

  return NS_OK;
}

/**
 * NOTE!! Forked into nsXMLContentSink. Please keep in sync.
 */
void
SinkContext::UpdateChildCounts()
{
  // Start from the top of the stack (growing upwards) and see if any
  // new content has been appended. If so, we recognize that reflows
  // have been generated for it and we should make sure that no
  // further reflows occur.  Note that we have to include stackPos == 0
  // to properly notify on kids of <html>.
  int32_t stackPos = mStackPos - 1;
  while (stackPos >= 0) {
    Node & node = mStack[stackPos];
    node.mNumFlushed = node.mContent->GetChildCount();

    stackPos--;
  }

  mNotifyLevel = mStackPos - 1;
}

/**
 * Flush any buffered text out by creating a text content object and
 * adding it to the content.
 */
nsresult
SinkContext::FlushText(bool* aDidFlush, bool aReleaseLast)
{
  nsresult rv = NS_OK;
  bool didFlush = false;

  if (mTextLength != 0) {
    if (mLastTextNode) {
      if ((mLastTextNodeSize + mTextLength) > mSink->mMaxTextRun) {
        mLastTextNodeSize = 0;
        mLastTextNode = nullptr;
        FlushText(aDidFlush, aReleaseLast);
      } else {
        bool notify = HaveNotifiedForCurrentContent();
        // We could probably always increase mInNotification here since
        // if AppendText doesn't notify it shouldn't trigger evil code.
        // But just in case it does, we don't want to mask any notifications.
        if (notify) {
          ++mSink->mInNotification;
        }
        rv = mLastTextNode->AppendText(mText, mTextLength, notify);
        if (notify) {
          --mSink->mInNotification;
        }

        mLastTextNodeSize += mTextLength;
        mTextLength = 0;
        didFlush = true;
      }
    } else {
      nsCOMPtr<nsIContent> textContent;
      rv = NS_NewTextNode(getter_AddRefs(textContent),
                          mSink->mNodeInfoManager);
      NS_ENSURE_SUCCESS(rv, rv);

      mLastTextNode = textContent;

      // Set the text in the text node
      mLastTextNode->SetText(mText, mTextLength, false);

      // Eat up the rest of the text up in state.
      mLastTextNodeSize += mTextLength;
      mTextLength = 0;

      rv = AddLeaf(mLastTextNode);
      NS_ENSURE_SUCCESS(rv, rv);

      didFlush = true;
    }
  }

  if (aDidFlush) {
    *aDidFlush = didFlush;
  }

  if (aReleaseLast) {
    mLastTextNodeSize = 0;
    mLastTextNode = nullptr;
    mLastTextCharWasCR = false;
  }

#ifdef DEBUG
  if (didFlush &&
      SINK_LOG_TEST(gSinkLogModuleInfo, SINK_ALWAYS_REFLOW)) {
    mSink->ForceReflow();
  }
#endif

  return rv;
}

nsresult
NS_NewHTMLContentSink(nsIHTMLContentSink** aResult,
                      nsIDocument* aDoc,
                      nsIURI* aURI,
                      nsISupports* aContainer,
                      nsIChannel* aChannel)
{
  NS_ENSURE_ARG_POINTER(aResult);

  nsRefPtr<HTMLContentSink> it = new HTMLContentSink();

  if (!it) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);

  NS_ENSURE_SUCCESS(rv, rv);

  *aResult = it;
  NS_ADDREF(*aResult);

  return NS_OK;
}

HTMLContentSink::HTMLContentSink()
{
  // Note: operator new zeros our memory

#ifdef DEBUG
  if (!gSinkLogModuleInfo) {
    gSinkLogModuleInfo = PR_NewLogModule("htmlcontentsink");
  }
#endif
}

HTMLContentSink::~HTMLContentSink()
{
  if (mNotificationTimer) {
    mNotificationTimer->Cancel();
  }

  int32_t numContexts = mContextStack.Length();

  if (mCurrentContext == mHeadContext && numContexts > 0) {
    // Pop off the second html context if it's not done earlier
    mContextStack.RemoveElementAt(--numContexts);
  }

  int32_t i;
  for (i = 0; i < numContexts; i++) {
    SinkContext* sc = mContextStack.ElementAt(i);
    if (sc) {
      sc->End();
      if (sc == mCurrentContext) {
        mCurrentContext = nullptr;
      }

      delete sc;
    }
  }

  if (mCurrentContext == mHeadContext) {
    mCurrentContext = nullptr;
  }

  delete mCurrentContext;

  delete mHeadContext;

  for (i = 0; uint32_t(i) < ArrayLength(mNodeInfoCache); ++i) {
    NS_IF_RELEASE(mNodeInfoCache[i]);
  }
}

NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLContentSink)

NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLContentSink, nsContentSink)
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mHTMLDocument)
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mRoot)
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mBody)
  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mHead)
  for (uint32_t i = 0; i < ArrayLength(tmp->mNodeInfoCache); ++i) {
    NS_IF_RELEASE(tmp->mNodeInfoCache[i]);
  }
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLContentSink,
                                                  nsContentSink)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mHTMLDocument)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mRoot)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mBody)
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mHead)
  for (uint32_t i = 0; i < ArrayLength(tmp->mNodeInfoCache); ++i) {
    NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mNodeInfoCache[i]");
    cb.NoteXPCOMChild(tmp->mNodeInfoCache[i]);
  }
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLContentSink)
  NS_INTERFACE_TABLE_BEGIN
    NS_INTERFACE_TABLE_ENTRY(HTMLContentSink, nsIContentSink)
    NS_INTERFACE_TABLE_ENTRY(HTMLContentSink, nsIHTMLContentSink)
#if DEBUG
    NS_INTERFACE_TABLE_ENTRY(HTMLContentSink, nsIDebugDumpContent)
#endif
  NS_INTERFACE_TABLE_END
NS_INTERFACE_TABLE_TAIL_INHERITING(nsContentSink)

NS_IMPL_ADDREF_INHERITED(HTMLContentSink, nsContentSink)
NS_IMPL_RELEASE_INHERITED(HTMLContentSink, nsContentSink)

static bool
IsScriptEnabled(nsIDocument *aDoc, nsIDocShell *aContainer)
{
  NS_ENSURE_TRUE(aDoc && aContainer, true);

  nsCOMPtr<nsIScriptGlobalObject> globalObject = aDoc->GetScriptGlobalObject();

  // Getting context is tricky if the document hasn't had its
  // GlobalObject set yet
  if (!globalObject) {
    nsCOMPtr<nsIScriptGlobalObjectOwner> owner = do_GetInterface(aContainer);
    NS_ENSURE_TRUE(owner, true);

    globalObject = owner->GetScriptGlobalObject();
    NS_ENSURE_TRUE(globalObject, true);
  }

  nsIScriptContext *scriptContext = globalObject->GetContext();
  NS_ENSURE_TRUE(scriptContext, true);

  JSContext* cx = scriptContext->GetNativeContext();
  NS_ENSURE_TRUE(cx, true);

  bool enabled = true;
  nsContentUtils::GetSecurityManager()->
    CanExecuteScripts(cx, aDoc->NodePrincipal(), &enabled);
  return enabled;
}

nsresult
HTMLContentSink::Init(nsIDocument* aDoc,
                      nsIURI* aURI,
                      nsISupports* aContainer,
                      nsIChannel* aChannel)
{
  NS_ENSURE_TRUE(aContainer, NS_ERROR_NULL_POINTER);

  nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
  if (NS_FAILED(rv)) {
    return rv;
  }

  aDoc->AddObserver(this);
  mIsDocumentObserver = true;
  mHTMLDocument = do_QueryInterface(aDoc);

  NS_ASSERTION(mDocShell, "oops no docshell!");

  // Find out if subframes are enabled
  if (mDocShell) {
    bool subFramesEnabled = true;
    mDocShell->GetAllowSubframes(&subFramesEnabled);
    if (subFramesEnabled) {
      mFramesEnabled = true;
    }
  }

  // Find out if scripts are enabled, if not, show <noscript> content
  if (IsScriptEnabled(aDoc, mDocShell)) {
    mScriptEnabled = true;
  }

  // Changed from 8192 to greatly improve page loading performance on
  // large pages.  See bugzilla bug 77540.
  mMaxTextRun = Preferences::GetInt("content.maxtextrun", 8191);

  nsCOMPtr<nsINodeInfo> nodeInfo;
  nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::html, nullptr,
                                           kNameSpaceID_XHTML,
                                           nsIDOMNode::ELEMENT_NODE);
  NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);

  // Make root part
  mRoot = NS_NewHTMLHtmlElement(nodeInfo.forget());
  if (!mRoot) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  NS_ASSERTION(mDocument->GetChildCount() == 0,
               "Document should have no kids here!");
  rv = mDocument->AppendChildTo(mRoot, false);
  NS_ENSURE_SUCCESS(rv, rv);

  // Make head part
  nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::head,
                                           nullptr, kNameSpaceID_XHTML,
                                           nsIDOMNode::ELEMENT_NODE);
  NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);

  mHead = NS_NewHTMLHeadElement(nodeInfo.forget());
  if (NS_FAILED(rv)) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  mRoot->AppendChildTo(mHead, false);

  mCurrentContext = new SinkContext(this);
  NS_ENSURE_TRUE(mCurrentContext, NS_ERROR_OUT_OF_MEMORY);
  mCurrentContext->Begin(eHTMLTag_html, mRoot, 0, -1);
  mContextStack.AppendElement(mCurrentContext);

#ifdef DEBUG
  nsAutoCString spec;
  (void)aURI->GetSpec(spec);
  SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_CALLS,
             ("HTMLContentSink::Init: this=%p url='%s'",
              this, spec.get()));
#endif
  return NS_OK;
}

NS_IMETHODIMP
HTMLContentSink::WillParse(void)
{
  return WillParseImpl();
}

NS_IMETHODIMP
HTMLContentSink::WillBuildModel(nsDTDMode aDTDMode)
{
  WillBuildModelImpl();

  if (mHTMLDocument) {
    nsCompatibility mode = eCompatibility_NavQuirks;
    switch (aDTDMode) {
      case eDTDMode_full_standards:
        mode = eCompatibility_FullStandards;
        break;
      case eDTDMode_almost_standards:
        mode = eCompatibility_AlmostStandards;
        break;
      default:
        break;
    }
    mHTMLDocument->SetCompatibilityMode(mode);
  }

  // Notify document that the load is beginning
  mDocument->BeginLoad();

  return NS_OK;
}

NS_IMETHODIMP
HTMLContentSink::DidBuildModel(bool aTerminated)
{
  DidBuildModelImpl(aTerminated);

  // Reflow the last batch of content
  if (mBody) {
    SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
               ("HTMLContentSink::DidBuildModel: layout final content"));
    mCurrentContext->FlushTags();
  } else if (!mLayoutStarted) {
    // We never saw the body, and layout never got started. Force
    // layout *now*, to get an initial reflow.
    SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
               ("HTMLContentSink::DidBuildModel: forcing reflow on empty "
                "document"));

    // NOTE: only force the layout if we are NOT destroying the
    // docshell. If we are destroying it, then starting layout will
    // likely cause us to crash, or at best waste a lot of time as we
    // are just going to tear it down anyway.
    bool bDestroying = true;
    if (mDocShell) {
      mDocShell->IsBeingDestroyed(&bDestroying);
    }

    if (!bDestroying) {
      StartLayout(false);
    }
  }

  ScrollToRef();

  // Make sure we no longer respond to document mutations.  We've flushed all
  // our notifications out, so there's no need to do anything else here.

  // XXXbz I wonder whether we could End() our contexts here too, or something,
  // just to make sure we no longer notify...  Or is the mIsDocumentObserver
  // thing sufficient?
  mDocument->RemoveObserver(this);
  mIsDocumentObserver = false;

  mDocument->EndLoad();

  DropParserAndPerfHint();

  return NS_OK;
}

NS_IMETHODIMP
HTMLContentSink::SetParser(nsParserBase* aParser)
{
  NS_PRECONDITION(aParser, "Should have a parser here!");
  mParser = aParser;
  return NS_OK;
}

NS_IMETHODIMP
HTMLContentSink::BeginContext(int32_t aPosition)
{
  NS_PRECONDITION(aPosition > -1, "out of bounds");

  if (!mCurrentContext) {
    NS_ERROR("Nonexistent context");

    return NS_ERROR_FAILURE;
  }

  // Flush everything in the current context so that we don't have
  // to worry about insertions resulting in inconsistent frame creation.
  mCurrentContext->FlushTags();

  // Sanity check.
  if (mCurrentContext->mStackPos <= aPosition) {
    NS_ERROR("Out of bounds position");
    return NS_ERROR_FAILURE;
  }

  int32_t insertionPoint = -1;
  nsHTMLTag nodeType      = mCurrentContext->mStack[aPosition].mType;
  nsGenericHTMLElement* content = mCurrentContext->mStack[aPosition].mContent;

  // If the content under which the new context is created
  // has a child on the stack, the insertion point is
  // before the last child.
  if (aPosition < (mCurrentContext->mStackPos - 1)) {
    insertionPoint = content->GetChildCount() - 1;
  }

  SinkContext* sc = new SinkContext(this);
  sc->Begin(nodeType,
            content,
            mCurrentContext->mStack[aPosition].mNumFlushed,
            insertionPoint);
  NS_ADDREF(sc->mSink);

  mContextStack.AppendElement(mCurrentContext);
  mCurrentContext = sc;
  return NS_OK;
}

NS_IMETHODIMP
HTMLContentSink::EndContext(int32_t aPosition)
{
  NS_PRECONDITION(mCurrentContext && aPosition > -1, "nonexistent context");

  uint32_t n = mContextStack.Length() - 1;
  SinkContext* sc = mContextStack.ElementAt(n);

  const SinkContext::Node &bottom = mCurrentContext->mStack[0];

  NS_ASSERTION(sc->mStack[aPosition].mType == bottom.mType,
               "ending a wrong context");

  mCurrentContext->FlushTextAndRelease();

  NS_ASSERTION(bottom.mContent->GetChildCount() == bottom.mNumFlushed,
               "Node at base of context stack not fully flushed.");

  // Flushing tags before the assertion on the previous line would
  // undoubtedly prevent the assertion from failing, but it shouldn't
  // be failing anyway, FlushTags or no.  Flushing here is nevertheless
  // a worthwhile precaution, since we lose some information (e.g.,
  // mInsertionPoints) when we end the current context.
  mCurrentContext->FlushTags();

  sc->mStack[aPosition].mNumFlushed = bottom.mNumFlushed;

  for (int32_t i = 0; i<mCurrentContext->mStackPos; i++) {
    NS_IF_RELEASE(mCurrentContext->mStack[i].mContent);
  }

  delete [] mCurrentContext->mStack;

  mCurrentContext->mStack      = nullptr;
  mCurrentContext->mStackPos   = 0;
  mCurrentContext->mStackSize  = 0;

  delete [] mCurrentContext->mText;

  mCurrentContext->mText       = nullptr;
  mCurrentContext->mTextLength = 0;
  mCurrentContext->mTextSize   = 0;

  NS_IF_RELEASE(mCurrentContext->mSink);

  delete mCurrentContext;

  mCurrentContext = sc;
  mContextStack.RemoveElementAt(n);
  return NS_OK;
}

nsresult
HTMLContentSink::CloseHTML()
{
  SINK_TRACE_NODE(SINK_TRACE_CALLS,
                 "HTMLContentSink::CloseHTML",
                 eHTMLTag_html, 0, this);

  if (mHeadContext) {
    if (mCurrentContext == mHeadContext) {
      uint32_t numContexts = mContextStack.Length();

      // Pop off the second html context if it's not done earlier
      mCurrentContext = mContextStack.ElementAt(--numContexts);
      mContextStack.RemoveElementAt(numContexts);
    }

    NS_ASSERTION(mHeadContext->mTextLength == 0, "Losing text");

    mHeadContext->End();

    delete mHeadContext;
    mHeadContext = nullptr;
  }

  return NS_OK;
}

nsresult
HTMLContentSink::OpenHead()
{
  nsresult rv = OpenHeadContext();
  return rv;
}

nsresult
HTMLContentSink::OpenBody(const nsIParserNode& aNode)
{
  SINK_TRACE_NODE(SINK_TRACE_CALLS,
                  "HTMLContentSink::OpenBody",
                  eHTMLTag_body,
                  mCurrentContext->mStackPos,
                  this);

  CloseHeadContext();  // do this just in case if the HEAD was left open!

  // Add attributes, if any, to the current BODY node
  if (mBody) {
    AddAttributes(aNode, mBody, true, true);
    return NS_OK;
  }

  nsresult rv = mCurrentContext->OpenContainer(aNode);

  if (NS_FAILED(rv)) {
    return rv;
  }

  mBody = mCurrentContext->mStack[mCurrentContext->mStackPos - 1].mContent;

  if (mCurrentContext->mStackPos > 1) {
    int32_t parentIndex    = mCurrentContext->mStackPos - 2;
    nsGenericHTMLElement *parent = mCurrentContext->mStack[parentIndex].mContent;
    int32_t numFlushed     = mCurrentContext->mStack[parentIndex].mNumFlushed;
    int32_t childCount = parent->GetChildCount();
    NS_ASSERTION(numFlushed < childCount, "Already notified on the body?");

    int32_t insertionPoint =
      mCurrentContext->mStack[parentIndex].mInsertionPoint;

    // XXX: I have yet to see a case where numFlushed is non-zero and
    // insertionPoint is not -1, but this code will try to handle
    // those cases too.

    uint32_t oldUpdates = mUpdatesInNotification;
    mUpdatesInNotification = 0;
    if (insertionPoint != -1) {
      NotifyInsert(parent, mBody, insertionPoint - 1);
    } else {
      NotifyAppend(parent, numFlushed);
    }
    mCurrentContext->mStack[parentIndex].mNumFlushed = childCount;
    if (mUpdatesInNotification > 1) {
      UpdateChildCounts();
    }
    mUpdatesInNotification = oldUpdates;
  }

  StartLayout(false);

  return NS_OK;
}

nsresult
HTMLContentSink::CloseBody()
{
  SINK_TRACE_NODE(SINK_TRACE_CALLS,
                  "HTMLContentSink::CloseBody",
                  eHTMLTag_body,
                  mCurrentContext->mStackPos - 1,
                  this);

  bool didFlush;
  nsresult rv = mCurrentContext->FlushTextAndRelease(&didFlush);
  if (NS_FAILED(rv)) {
    return rv;
  }

  // Flush out anything that's left
  SINK_TRACE(gSinkLogModuleInfo, SINK_TRACE_REFLOW,
             ("HTMLContentSink::CloseBody: layout final body content"));

  mCurrentContext->FlushTags();
  mCurrentContext->CloseContainer(eHTMLTag_body);

  return NS_OK;
}

NS_IMETHODIMP
HTMLContentSink::IsEnabled(int32_t aTag, bool* aReturn)
{
  nsHTMLTag theHTMLTag = nsHTMLTag(aTag);

  if (theHTMLTag == eHTMLTag_script) {
    *aReturn = mScriptEnabled;
  } else if (theHTMLTag == eHTMLTag_frameset) {
    *aReturn = mFramesEnabled;
  } else {
    *aReturn = false;
  }

  return NS_OK;
}

NS_IMETHODIMP
HTMLContentSink::OpenContainer(const nsIParserNode& aNode)
{
  nsresult rv = NS_OK;

  switch (aNode.GetNodeType()) {
    case eHTMLTag_frameset:
      MOZ_NOT_REACHED("Must not use HTMLContentSink for frames.");
      rv = NS_ERROR_NOT_IMPLEMENTED;
      break;
    case eHTMLTag_head:
      rv = OpenHeadContext();
      if (NS_SUCCEEDED(rv)) {
        rv = AddAttributes(aNode, mHead, true, mHaveSeenHead);
        mHaveSeenHead = true;
      }
      break;
    case eHTMLTag_body:
      rv = OpenBody(aNode);
      break;
    case eHTMLTag_html:
      if (mRoot) {
        // If we've already hit this code once, need to check for
        // already-present attributes on the root.
        AddAttributes(aNode, mRoot, true, mNotifiedRootInsertion);
        if (!mNotifiedRootInsertion) {
          NotifyRootInsertion();
        }
        ProcessOfflineManifest(mRoot);
      }
      break;
    case eHTMLTag_form:
      MOZ_NOT_REACHED("Must not use HTMLContentSink for forms.");
      rv = NS_ERROR_NOT_IMPLEMENTED;
      break;
    default:
      rv = mCurrentContext->OpenContainer(aNode);
      break;
  }

  return rv;
}

NS_IMETHODIMP
HTMLContentSink::CloseContainer(const eHTMLTags aTag)
{
  nsresult rv = NS_OK;

  switch (aTag) {
    case eHTMLTag_frameset:
      MOZ_NOT_REACHED("Must not use HTMLContentSink for frames.");
      rv = NS_ERROR_NOT_IMPLEMENTED;
      break;
    case eHTMLTag_head:
      CloseHeadContext();
      break;
    case eHTMLTag_body:
      rv = CloseBody();
      break;
    case eHTMLTag_html:
      rv = CloseHTML();
      break;
    case eHTMLTag_form:
      MOZ_NOT_REACHED("Must not use HTMLContentSink for forms.");
      rv = NS_ERROR_NOT_IMPLEMENTED;
      break;
    default:
      rv = mCurrentContext->CloseContainer(aTag);
      break;
  }

  return rv;
}

NS_IMETHODIMP
HTMLContentSink::CloseMalformedContainer(const eHTMLTags aTag)
{
  return mCurrentContext->CloseContainer(aTag);
}

NS_IMETHODIMP
HTMLContentSink::AddLeaf(const nsIParserNode& aNode)
{
  nsresult rv;

  nsHTMLTag nodeType = nsHTMLTag(aNode.GetNodeType());
  switch (nodeType) {
  case eHTMLTag_link:
    rv = NS_ERROR_NOT_IMPLEMENTED;
    MOZ_NOT_REACHED("Must not use HTMLContentSink for links.");

    break;
  default:
    rv = mCurrentContext->AddLeaf(aNode);

    break;
  }

  return rv;
}

NS_IMETHODIMP
HTMLContentSink::DidProcessTokens(void)
{
  return NS_OK;
}

NS_IMETHODIMP
HTMLContentSink::WillProcessAToken(void)
{
  return NS_OK;
}

NS_IMETHODIMP
HTMLContentSink::DidProcessAToken(void)
{
  return DidProcessATokenImpl();
}

NS_IMETHODIMP
HTMLContentSink::WillInterrupt()
{
  return WillInterruptImpl();
}

NS_IMETHODIMP
HTMLContentSink::WillResume()
{
  return WillResumeImpl();
}

nsresult
HTMLContentSink::OpenHeadContext()
{
  if (mCurrentContext && mCurrentContext->IsCurrentContainer(eHTMLTag_head))
    return NS_OK;

  // Flush everything in the current context so that we don't have
  // to worry about insertions resulting in inconsistent frame creation.
  //
  // Try to do this only if needed (costly), i.e., only if we are sure
  // we are changing contexts from some other context to the head.
  //
  // PERF: This call causes approximately a 2% slowdown in page load time
  // according to jrgm's page load tests, but seems to be a necessary evil
  if (mCurrentContext && (mCurrentContext != mHeadContext)) {
    mCurrentContext->FlushTags();
  }

  if (!mHeadContext) {
    mHeadContext = new SinkContext(this);
    NS_ENSURE_TRUE(mHeadContext, NS_ERROR_OUT_OF_MEMORY);

    nsresult rv = mHeadContext->Begin(eHTMLTag_head, mHead, 0, -1);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  mContextStack.AppendElement(mCurrentContext);
  mCurrentContext = mHeadContext;

  return NS_OK;
}

void
HTMLContentSink::CloseHeadContext()
{
  if (mCurrentContext) {
    if (!mCurrentContext->IsCurrentContainer(eHTMLTag_head))
      return;

    mCurrentContext->FlushTextAndRelease();
    mCurrentContext->FlushTags();
  }

  if (!mContextStack.IsEmpty())
  {
    uint32_t n = mContextStack.Length() - 1;
    mCurrentContext = mContextStack.ElementAt(n);
    mContextStack.RemoveElementAt(n);
  }
}

#ifdef DEBUG
void
HTMLContentSink::ForceReflow()
{
  mCurrentContext->FlushTags();
}
#endif

void
HTMLContentSink::NotifyInsert(nsIContent* aContent,
                              nsIContent* aChildContent,
                              int32_t aIndexInContainer)
{
  if (aContent && aContent->GetCurrentDoc() != mDocument) {
    // aContent is not actually in our document anymore.... Just bail out of
    // here; notifying on our document for this insert would be wrong.
    return;
  }

  mInNotification++;

  {
    // Scope so we call EndUpdate before we decrease mInNotification
    MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_CONTENT_MODEL, !mBeganUpdate);
    nsNodeUtils::ContentInserted(NODE_FROM(aContent, mDocument),
                                 aChildContent, aIndexInContainer);
    mLastNotificationTime = PR_Now();
  }

  mInNotification--;
}

void
HTMLContentSink::NotifyRootInsertion()
{
  NS_PRECONDITION(!mNotifiedRootInsertion, "Double-notifying on root?");
  NS_ASSERTION(!mLayoutStarted,
               "How did we start layout without notifying on root?");
  // Now make sure to notify that we have now inserted our root.  If
  // there has been no initial reflow yet it'll be a no-op, but if
  // there has been one we need this to get its frames constructed.
  // Note that if mNotifiedRootInsertion is true we don't notify here,
  // since that just means there are multiple <html> tags in the
  // document; in those cases we just want to put all the attrs on one
  // tag.
  mNotifiedRootInsertion = true;
  int32_t index = mDocument->IndexOf(mRoot);
  NS_ASSERTION(index != -1, "mRoot not child of document?");
  NotifyInsert(nullptr, mRoot, index);

  // Now update the notification information in all our
  // contexts, since we just inserted the root and notified on
  // our whole tree
  UpdateChildCounts();
}

bool
HTMLContentSink::IsMonolithicContainer(nsHTMLTag aTag)
{
  if (aTag == eHTMLTag_tr     ||
      aTag == eHTMLTag_select ||
      aTag == eHTMLTag_applet ||
      aTag == eHTMLTag_object) {
    return true;
  }

  return false;
}

void
HTMLContentSink::UpdateChildCounts()
{
  uint32_t numContexts = mContextStack.Length();
  for (uint32_t i = 0; i < numContexts; i++) {
    SinkContext* sc = mContextStack.ElementAt(i);

    sc->UpdateChildCounts();
  }

  mCurrentContext->UpdateChildCounts();
}

void
HTMLContentSink::FlushPendingNotifications(mozFlushType aType)
{
  // Only flush tags if we're not doing the notification ourselves
  // (since we aren't reentrant)
  if (!mInNotification) {
    // Only flush if we're still a document observer (so that our child counts
    // should be correct).
    if (mIsDocumentObserver) {
      if (aType >= Flush_ContentAndNotify) {
        FlushTags();
      }
      else if (mCurrentContext) {
        mCurrentContext->FlushText();
      }
    }
    if (aType >= Flush_InterruptibleLayout) {
      // Make sure that layout has started so that the reflow flush
      // will actually happen.
      StartLayout(true);
    }
  }
}

nsresult
HTMLContentSink::FlushTags()
{
  if (!mNotifiedRootInsertion) {
    NotifyRootInsertion();
    return NS_OK;
  }

  return mCurrentContext ? mCurrentContext->FlushTags() : NS_OK;
}

NS_IMETHODIMP
HTMLContentSink::SetDocumentCharset(nsACString& aCharset)
{
  if (mDocShell) {
    // the following logic to get muCV is copied from
    // nsHTMLDocument::StartDocumentLoad
    // We need to call muCV->SetPrevDocCharacterSet here in case
    // the charset is detected by parser DetectMetaTag
    nsCOMPtr<nsIMarkupDocumentViewer> muCV;
    nsCOMPtr<nsIContentViewer> cv;
    mDocShell->GetContentViewer(getter_AddRefs(cv));
    if (cv) {
       muCV = do_QueryInterface(cv);
    } else {
      // in this block of code, if we get an error result, we return
      // it but if we get a null pointer, that's perfectly legal for
      // parent and parentContentViewer

      nsCOMPtr<nsIDocShellTreeItem> docShellAsItem =
        do_QueryInterface(mDocShell);
      NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);

      nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
      docShellAsItem->GetSameTypeParent(getter_AddRefs(parentAsItem));

      nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
      if (parent) {
        nsCOMPtr<nsIContentViewer> parentContentViewer;
        nsresult rv =
          parent->GetContentViewer(getter_AddRefs(parentContentViewer));
        if (NS_SUCCEEDED(rv) && parentContentViewer) {
          muCV = do_QueryInterface(parentContentViewer);
        }
      }
    }

    if (muCV) {
      muCV->SetPrevDocCharacterSet(aCharset);
    }
  }

  if (mDocument) {
    mDocument->SetDocumentCharacterSet(aCharset);
  }

  return NS_OK;
}

nsISupports *
HTMLContentSink::GetTarget()
{
  return mDocument;
}

bool
HTMLContentSink::IsScriptExecuting()
{
  return IsScriptExecutingImpl();
}

#ifdef DEBUG
/**
 *  This will dump content model into the output file.
 *
 *  @update  harishd 05/25/00
 *  @param
 *  @return  NS_OK all went well, error on failure
 */

NS_IMETHODIMP
HTMLContentSink::DumpContentModel()
{
  FILE* out = ::fopen("rtest_html.txt", "a");
  if (out) {
    if (mDocument) {
      Element* root = mDocument->GetRootElement();
      if (root) {
        if (mDocumentURI) {
          nsAutoCString buf;
          mDocumentURI->GetSpec(buf);
          fputs(buf.get(), out);
        }

        fputs(";", out);
        root->DumpContent(out, 0, false);
        fputs(";\n", out);
      }
    }

    fclose(out);
  }

  return NS_OK;
}
#endif


text:
package io.fabric8.cdi.weld;

import org.apache.deltaspike.core.api.config.ConfigProperty;

import javax.inject.Inject;

public class ConfigBean {

    @Inject
    @ConfigProperty(name = "TEST", defaultValue = "value")
    private String property;

    public String getProperty() {
        return property;
    }
}


text:
int compile(char *in, char *out, int log);

#endif  // COMPILER_H