text:
(function(metricsWatcher, $) {

	/**
	 * Add a Gauge type graph to your page.
	 *
	 * @param divId The id of the div to draw the graph in
	 * @param className The class name of your metrics data, from the metrics servlet
	 * @param metricName The metric name of your metrics data, from the metrics servlet
	 * @param title The user-displayed title of this graph
	 */
	metricsWatcher.addGauge = function(divId, className, metricName, title) {
		var metricInfo = new MetricInfo(divId, className, metricName, null, title, 'gauges', null);
		graphs.push(metricInfo);
	};

	/**
	 * Add a Meter type graph to your page.
	 *
	 * @param divId The id of the div to draw the graph in
	 * @param className The class name of your metrics data, from the metrics servlet
	 * @param metricName The metric name of your metrics data, from the metrics servlet
	 * @param max What the max value target is, used to determine the % width of progress bars for this graph
	 * @param title The user-displayed title of this graph
	 */
	metricsWatcher.addMeter = function(divId, className, metricName, max, title, eventType) {
		if (eventType == undefined) eventType = 'Calls';
		var metricInfo = new MetricInfo(divId, className, metricName, max, title, 'meters', eventType);
		metricInfo.eventType = eventType;
		graphs.push(metricInfo);
	};

	/**
	 * Add a Counter graph
	 *
	 * @param divId The id of the div to draw the graph in
	 * @param className The class name of your metrics data, from the metrics servlet
	 * @param metricName The metric name of your metrics data, from the metrics servlet
	 * @param max What the max value target is, used to determine the % width of progress bars for this graph
	 * @param title The user-displayed title of this graph
	 */
	metricsWatcher.addCounter = function(divId, className, metricName, max, title) {
		var metricInfo = new MetricInfo(divId, className, metricName, max, title, 'counters', null);
		graphs.push(metricInfo);
	};

		/**
	 * Add a standalone Histogram graph
	 *
	 * @param divId The id of the div to draw the graph in
	 * @param className The class name of your metrics data, from the metrics servlet
	 * @param metricName The metric name of your metrics data, from the metrics servlet
	 * @param max What the max value target is, used to determine the % width of progress bars for this graph
	 * @param title The user-displayed title of this graph
	 */
	metricsWatcher.addHistogram = function(divId, className, metricName, max, title){
		var metricInfo = new MetricInfo(divId, className, metricName, (!max ? 1: max), title, 'histograms', null);
		graphs.push(metricInfo);
	};

	/**
	 * Add a linked Counter graph. Linked Counters differ from a plain counter graph in that both the numerator and denominator
	 * of a linked counter graph each come from individual Counter Metrics.
	 *
	 * @param divId The id of the div to draw the graph in
	 * @param className The class name of your metrics data, from the metrics servlet
	 * @param metricName The metric name of your metrics data, from the metrics servlet
	 * @param maxClassName
	 * @param maxMetricName
	 * @param title The user-displayed title of this graph
	 */
	metricsWatcher.addLinkedCounter = function(divId, className, metricName, maxClassName, maxMetricName, title) {
		var metricInfo = new MetricInfo(divId, className, metricName, null, title, "counters", null);
		if(!metricInfo)
			metricInfo = new MetricInfo(divId, className, metricName, null, title, "timers", null);

		metricInfo.maxClassName = maxClassName;
		metricInfo.maxMetricName = maxMetricName;

		metricInfo.getMax = function(json) {
			var maxNode = this.getMetricNode(this.maxClassName, this.maxMetricName, json);
			return maxNode["count"];
		};

			metricInfo.getMetricNode = function getMetricNode(className, metricName, jsonRoot) {

				var node=!(jsonRoot["counters"][className+'.'+metricName]) ? null : jsonRoot["counters"][className+'.'+metricName];
				if(node){
					return node;
				}else{
					return !(jsonRoot["timers"][className+'.'+metricName]) ? null : jsonRoot["timers"][className+'.'+metricName];
				}
			};

		graphs.push(metricInfo);
	};

	/**
	 * Add a Timer graph. This will include a Meter, Timing Info, and a Histogram.
	 *
	 * @param divId The id of the div to draw the graph in
	 * @param className The class name of your metrics data, from the metrics servlet
	 * @param metricName The metric name of your metrics data, from the metrics servlet
	 * @param max The max target value for the Meter, showing frequency
	 * @param title The user-displayed title of this graph
	 * @param eventType a name for this event type
	 * @param durationMax The max target value for duration
	 */
	metricsWatcher.addTimer = function(divId, className, metricName, max, title, eventType, durationMax) {
		var timer = addTimerInternal(divId, className, metricName, max, title, eventType, durationMax, false);
		graphs.push(timer);
	};

	/**
	 * Add an ehcache graph.
	 *
	 * @param divId The id of the div to draw the graph in
	 * @param className The class name of your metrics data, from the metrics servlet
	 * @param title The user-displayed title of this graph
	 */
	metricsWatcher.addCache = function(divId, className, title) {
		var metricInfo = new MetricInfo(divId, className, null, null, title, "caches", null);

		metricInfo.components = {
			gauges : [
				new MetricInfo(null, className, "hits", null, "Hits", "gauges", null),
				new MetricInfo(null, className, "misses", null, "Misses", "gauges", null),
				new MetricInfo(null, className, "objects", null, "Objects", "gauges", null),
				new MetricInfo(null, className, "eviction-count", null, "Eviction Count", "gauges", null),
				new MetricInfo(null, className, "in-memory-hits", null, "In Memory Hits", "gauges", null),
				new MetricInfo(null, className, "in-memory-misses", null, "In Memory Misses", "gauges", null),
				new MetricInfo(null, className, "in-memory-objects", null, "In Memory Objects", "gauges", null),
				new MetricInfo(null, className, "off-heap-hits", null, "Off Heap Hits", "gauges", null),
				new MetricInfo(null, className, "off-heap-misses", null, "Off Heap Misses", "gauges", null),
				new MetricInfo(null, className, "off-heap-objects", null, "Off Heap Objects", "gauges", null),
				new MetricInfo(null, className, "on-disk-hits", null, "On Disk Hits", "gauges", null),
				new MetricInfo(null, className, "on-disk-misses", null, "On Disk Misses", "gauges", null),
				new MetricInfo(null, className, "on-disk-objects", null, "On Disk Objects", "gauges", null),
				new MetricInfo(null, className, "mean-get-time", null, "Mean Get Time", "gauges", null),
				new MetricInfo(null, className, "mean-search-time", null, "Mean Search Time", "gauges", null),
				new MetricInfo(null, className, "searches-per-second", null, "Searches Per Sec", "gauges", null),
				new MetricInfo(null, className, "writer-queue-size", null, "Writer Queue Size", "gauges", null),
				new MetricInfo(null, className, "accuracy", null, "Accuracy", "gauges", null)
			]
		};
		metricInfo.getTimer = addTimerInternal(divId + "gettimer", className, "gets", 5, "Get", "get", 1, true);
		metricInfo.putTimer = addTimerInternal(divId + "puttimer", className, "puts", 5, "Put", "put", 1, true);

		graphs.push(metricInfo);
	};

	/**
	 * Add a JVM graph.
	 *
	 * @param divId The id of the div to draw the graph in
	 * @param className The class name of your metrics data, from the metrics servlet
	 * @param title The user-displayed title of this graph
	 */
	metricsWatcher.addJvm = function(divId, className, title) {
		var metricInfo = new MetricInfo(divId, className, null, null, title, "jvms", null);
		graphs.push(metricInfo);
	};

	/**
	 * Add a web server graph.
	 *
	 * @param divId The id of the div to draw the graph in
	 * @param className The class name of your metrics data, from the metrics servlet
	 * @param title The user-displayed title of this graph
	 */
	metricsWatcher.addWeb = function(divId, className, title) {
		var metricInfo = new MetricInfo(divId, className, null, null, title, "webs", null);

		metricInfo.components = {
			meters : [
				new MetricInfo(divId + " td.responseCodesOkGraph", className, "responseCodes.ok", 10, "OK Responses", "meters", null),
				new MetricInfo(divId + " td.responseCodesBadRequestGraph", className, "responseCodes.badRequest", 10, "Bad Requests", "meters", null),
				new MetricInfo(divId + " td.responseCodesCreatedGraph", className, "responseCodes.created", 10, "Created Responses", "meters", null),
				new MetricInfo(divId + " td.responseCodesNoContentGraph", className, "responseCodes.noContent", 10, "No Content Responses", "meters", null),
				new MetricInfo(divId + " td.responseCodesNotFoundGraph", className, "responseCodes.notFound", 10, "Not Found Responses", "meters", null),
				new MetricInfo(divId + " td.responseCodesOtherGraph", className, "responseCodes.other", 10, "Other Responses", "meters", null),
				new MetricInfo(divId + " td.responseCodesServerErrorGraph", className, "responseCodes.serverError", 10, "Server Error Responses", "meters", null)
			],
			activeRequestsInfo : new MetricInfo(divId + " td.activeRequestsGraph", className, "activeRequests", 10, "Active Requests", "counters", null),
			requestsInfo : addTimerInternal(divId + " td.requestsGraph", className, "requests", 100, "Requests", "requests", 100, true)
		};

		graphs.push(metricInfo);
	};

	/**
	 * Add a log4j logged events graph.
	 *
	 * @param divId The id of the div to draw the graph in
	 * @param className The class name of your metrics data, from the metrics servlet
	 * @param title The user-displayed title of this graph
	 */
	metricsWatcher.addLog4j = function(divId, className, title) {
		var metricInfo = new MetricInfo(divId, className, null, null, title, "log4js", null);

		metricInfo.components = {
			meters : [
				new MetricInfo(divId + " td.all", className, "all", 100, "all", "meters", null),
				new MetricInfo(divId + " td.fatal", className, "fatal", 100, "fatal", "meters", null),
				new MetricInfo(divId + " td.error", className, "error", 100, "error", "meters", null),
				new MetricInfo(divId + " td.warn", className, "warn", 100, "warn", "meters", null),
				new MetricInfo(divId + " td.info", className, "info", 100, "info", "meters", null),
				new MetricInfo(divId + " td.debug", className, "debug", 100, "debug", "meters", null),
				new MetricInfo(divId + " td.trace", className, "trace", 100, "trace", "meters", null)
			]
		};

		graphs.push(metricInfo);
	};

	/**
	 * Initialized each of the graphs that you have added through addXXX() calls,
	 * and draws them on the screen for the first time
	 */
	metricsWatcher.initGraphs = function() {
		// draw all graphs for the first time
		for (var i = 0; i < graphs.length; i++) {
			if (graphs[i].type == "gauges")
				drawGauge(graphs[i]);
			else if (graphs[i].type == "meters")
				drawMeter(graphs[i]);
			else if (graphs[i].type == "counters" || graphs[i].type == "linkedTimerCounters")
				drawCounter(graphs[i]);
			else if (graphs[i].type == "histograms")
				drawHistogram(graphs[i]);
			else if (graphs[i].type == "timers")
				drawTimer(graphs[i]);
			else if (graphs[i].type == "caches")
				drawCache(graphs[i]);
			else if (graphs[i].type == "jvms")
				drawJvm(graphs[i]);
			else if (graphs[i].type == "webs")
				drawWeb(graphs[i]);
			else if (graphs[i].type == "log4js")
				drawLog4j(graphs[i]);
			else
				alert("Unknown meter info type: " + graphs[i].type);
		}
	};

	/**
	 * Update the existing graphs with new data. You can call this method as frequently as you would
	 * like to, and all graph info will be updated.
	 *
	 * @param json The root of the json node returned from your ajax call to the metrics servlet
	 */
	metricsWatcher.updateGraphs = function(json) {
		for (var i = 0; i < graphs.length; i++) {
			if (graphs[i].type == "gauges")
				updateGauge(graphs[i], json);
			else if (graphs[i].type == "meters")
				updateMeter(graphs[i], json);
			else if (graphs[i].type == "counters" || graphs[i].type == "linkedTimerCounters")
				updateCounter(graphs[i], json);
			else if (graphs[i].type == "histograms")
				updateHistogram(graphs[i], json);
			else if (graphs[i].type == "timers")
				updateTimer(graphs[i], json);
			else if (graphs[i].type == "caches")
				updateCache(graphs[i], json);
			else if (graphs[i].type == "jvms")
				updateJvm(graphs[i], json);
			else if (graphs[i].type == "webs")
				updateWeb(graphs[i], json);
			else if (graphs[i].type == "log4js")
				updateLog4j(graphs[i], json);
			else
				alert("Unknown meter info type: " + graphs[i].type);
		}
	};

	/*
	 * Private Methods
	 */
	var graphs = [];

  function MetricInfo(divId, className, metricName, max, title, type, subTitle) {
		this.divId = divId;
		this.className = className;
		this.metricName = metricName;
		this.max = max;
		this.title = title;
		this.type = type;
    this.subTitle = subTitle;

		this.getMax = function(json) {
			return this.max;
		};
		this.getMetricNode = function getMetricNode(className, metricName, jsonRoot) {
			return !(jsonRoot[type][className+'.'+metricName]) ? null : jsonRoot[type][className+'.'+metricName];
		};

    this.getSubTitle = function() {
      if (this.subTitle != null) {
        return this.subTitle;
      } else {
        // fallback and use title
        return this.title;
      }
    }
	}

	function calculatePercentage(currentVal, maxVal) {
		var p = (currentVal / maxVal) * 100;
		return p.toFixed(0);
	}

	function formatNumber(varNumber, n) {
		if (isNaN(n)) n = 1;

		return !isNaN(varNumber)?varNumber.toFixed(n):n;
	}

	function capitalizeFirstLetter(input) {
		return input.charAt(0).toUpperCase() + input.slice(1);
	}

	function addTimerInternal(divId, className, metricName, max, title, eventType, durationMax, isNested) {
		var metricInfo = new MetricInfo(divId, className, metricName, max, title, 'timers', eventType);

		metricInfo.getMeterInfo = function() {
			var myDivId = this.divId + " div.timerGraph div.meterGraph";
			var retVal = new MetricInfo(myDivId, this.className, this.metricName, this.max, "Frequency", 'timers', null);

			retVal.getMetricNode = function(className, metricName, jsonRoot) {
				return !jsonRoot['timers'][className+'.'+metricName] ? null : jsonRoot['timers'][className+'.'+metricName];
			};

			retVal.eventType = eventType;
			return retVal;
		};

		metricInfo.getTimerStatsDivId = function() {
			return "#" + this.divId + " div.timerGraph div.timerStatsGraph";
		};
		metricInfo.getTimerHistogramDivId = function() {
			return "#" + this.divId + " div.timerGraph div.timerHistogram";
		};
		metricInfo.durationMax = durationMax;
		metricInfo.isNested = isNested;

		return metricInfo;
	}

	/*
	 * Counter methods
	 */
	function drawCounter(counterInfo) {
		var parentDiv = $("#" + counterInfo.divId);
		var html = "

" + counterInfo.title
				+ "

";
		parentDiv.html(html);
	}

	function updateCounter(counterInfo, json) {
		var metricData = counterInfo.getMetricNode(counterInfo.className, counterInfo.metricName, json);
		var pct = calculatePercentage(metricData.count, counterInfo.getMax(json));

		$("#" + counterInfo.divId + " div.progress div.progress-bar").css("width", pct + "%");
		$("#" + counterInfo.divId + " div.progress div.progress-bar").html(metricData.count + "/" + counterInfo.getMax(json));
	}

	/*
	 * Timer methods
	 */
	function drawTimer(timerInfo) {
		var parentDiv = $("#" + timerInfo.divId);

		var nested = (timerInfo.isNested) ? " nested" : "";
		var html =
          '
'
        + '
'
				+ '
'
				+ '
'
				+ '
'
        +            ((timerInfo.isNested)
                       ? ''
                       : '')
				+            timerInfo.title + ''
				+ '
'
				+ '
'
				+ '
'
				+ '
'
				+ '

'
				+ '

'
				+ '

'
				+ '
'
        + '
'
        + '
'
        + '
'
        + '
';
		parentDiv.html(html);

		drawMeter(timerInfo.getMeterInfo());
		drawDurationStats(timerInfo);
		drawDurationHistogram(timerInfo);
	};

	function drawDurationStats(timerInfo) {
		var html = "
Duration

"
			+ addMeterRow("Min", "min")
			+ addMeterRow("Mean", "mean")
			+ addMeterRow("Max", "max")
			+ addMeterRow("Std Dev", "stddev")
			+ "

";
		var parentDiv = $(timerInfo.getTimerStatsDivId());
		parentDiv.html(html);
	}

	function drawDurationHistogram(timerInfo) {
		var html = "
 " +(timerInfo.isNested?  "Histogram" :timerInfo.getSubTitle()) + "

Percentiles

"
			+ addMeterRow("99.9%", "p999")
			+ addMeterRow("99%", "p99")
			+ addMeterRow("98%", "p98")
			+ addMeterRow("95%", "p95")
			+ addMeterRow("75%", "p75")
			+ addMeterRow("50%", "p50")
			+ "

";
		var parentDiv = $(timerInfo.getTimerHistogramDivId());
		parentDiv.html(html);
	}

	function updateTimer(timerInfo, json) {
		updateMeter(timerInfo.getMeterInfo(), json);
		updateDurationStats(timerInfo, json);
		updateDurationHistogram(timerInfo, json);
	}

	function updateDurationStats(timerInfo, json) {
		var metricNode = timerInfo.getMetricNode(timerInfo.className, timerInfo.metricName, json);
		if (!metricNode) return;

		var timeUnitDiv = $(timerInfo.getTimerStatsDivId() + " div.timeUnit");
		timeUnitDiv.html(capitalizeFirstLetter(metricNode["duration_units"]));

		updateDuration(timerInfo.getTimerStatsDivId(), metricNode, "min", timerInfo.durationMax);
		updateDuration(timerInfo.getTimerStatsDivId(), metricNode, "mean", timerInfo.durationMax);
		updateDuration(timerInfo.getTimerStatsDivId(), metricNode, "max", timerInfo.durationMax);
		updateDuration(timerInfo.getTimerStatsDivId(), metricNode, "stddev", timerInfo.durationMax);
	}

	function updateDuration(timerStatsDivId, durationData, style, max) {
		$(timerStatsDivId + " tr." + style + " td.progressValue").html(formatNumber(durationData[style]));
		$(timerStatsDivId + " tr." + style + " td.progressBar div.progress div.progress-bar")
			.css("width", calculatePercentage(durationData[style], max) + "%");
	}

	function updateDurationHistogram(timerInfo, json) {
		var metricNode = timerInfo.getMetricNode(timerInfo.className, timerInfo.metricName, json);
		if (!metricNode) return;

		updateDuration(timerInfo.getTimerHistogramDivId(), metricNode, "p999", timerInfo.durationMax);
		updateDuration(timerInfo.getTimerHistogramDivId(), metricNode, "p99", timerInfo.durationMax);
		updateDuration(timerInfo.getTimerHistogramDivId(), metricNode, "p98", timerInfo.durationMax);
		updateDuration(timerInfo.getTimerHistogramDivId(), metricNode, "p95", timerInfo.durationMax);
		updateDuration(timerInfo.getTimerHistogramDivId(), metricNode, "p75", timerInfo.durationMax);
		updateDuration(timerInfo.getTimerHistogramDivId(), metricNode, "p50", timerInfo.durationMax);
	}

/*
 * Histogram methods
 */

	function drawHistogram(histogramInfo) {
		var parentDiv = $("#" + histogramInfo.divId);
		var html = "
"
			+ "
 " +(histogramInfo.isNested?  "Histogram" :histogramInfo.title) + "
"
			+ "
"
			+ "
"
				+ "
Count	Min	MaxMean
"
				+ "

"
			+ "
"
			+	"
Percentiles
"
			+"
"
			+ addMeterRow("99.9%", "p999")
			+ addMeterRow("99%", "p99")
			+ addMeterRow("98%", "p98")
			+ addMeterRow("95%", "p95")
			+ addMeterRow("75%", "p75")
			+ addMeterRow("50%", "p50")
			+ "

";
		parentDiv.html(html);
	}

	function updateHistogram(histogramInfo, json) {
		var metricNode = histogramInfo.getMetricNode(histogramInfo.className, histogramInfo.metricName, json);
		$("#" + histogramInfo.divId +  " td.countVal").html(formatNumber(metricNode['count'],0));
		$("#" + histogramInfo.divId +  " td.minVal").html(formatNumber(metricNode['min'],0));
		$("#" + histogramInfo.divId +  " td.maxVal").html(formatNumber(metricNode['max'],0));
		$("#" + histogramInfo.divId +  " td.meanVal").html(formatNumber(metricNode['mean'],0));

		setMeterRow(histogramInfo, metricNode, "p999", "p999", histogramInfo.max);
		setMeterRow(histogramInfo, metricNode, "p99", "p99", histogramInfo.max);
		setMeterRow(histogramInfo, metricNode, "p98", "p98", histogramInfo.max);
		setMeterRow(histogramInfo, metricNode, "p95", "p95", histogramInfo.max);
		setMeterRow(histogramInfo, metricNode, "p75", "p75", histogramInfo.max);
		setMeterRow(histogramInfo, metricNode, "p50", "p50", histogramInfo.max);
	}

	/*
	 * Meter methods
	 */
	function drawMeter(meterInfo) {
		var parentDiv = $("#" + meterInfo.divId);

		var html = "

" + meterInfo.title
			+ "

"
			+ addMeterRow("1 min", "onemin")
			+ addMeterRow("5 min", "fivemin")
			+ addMeterRow("15 min", "fifteenmin")
			+ addMeterRow("Mean", "mean")
			+ "

";
		parentDiv.html(html);
	}

	function addMeterRow(type, className) {
		return "
" + type + "	"
			+ "

"
			+ "
	0
";
	}

	function updateMeter(meterInfo, json) {
		var metricData = meterInfo.getMetricNode(meterInfo.className, meterInfo.metricName, json);
		if (metricData) {
			updateMeterData(meterInfo, metricData);
		}
	}

	function updateMeterData(meterInfo, meterData) {
		// set the big counter
		var gaugeDiv = $("#" + meterInfo.divId + " div.counterVal");

		gaugeDiv.html(meterData.rate_units + " (" + meterData.count + " total)");

		var maxRate = Math.max(meterData['mean_rate'],meterData['m1_rate'],meterData['m5_rate'],meterData['m15_rate']);

		// set the mean count
		setMeterRow(meterInfo, meterData, "mean_rate", "mean", maxRate);
		setMeterRow(meterInfo, meterData, "m1_rate", "onemin", maxRate);
		setMeterRow(meterInfo, meterData, "m5_rate", "fivemin", maxRate);
		setMeterRow(meterInfo, meterData, "m15_rate", "fifteenmin", maxRate);
	}

	function setMeterRow(meterInfo, meterData, rowType, rowStyle) {
		setMeterRow(meterInfo, meterData, rowType, rowStyle, meterInfo.max);
	}

	function setMeterRow(meterInfo, meterData, rowType, rowStyle, max) {
		$("#" + meterInfo.divId + " tr." + rowStyle + " td.progressValue").html(formatNumber(meterData[rowType]));
		$("#" + meterInfo.divId + " tr." + rowStyle + " td.progressBar div.progress div.progress-bar")
			.css("width", calculatePercentage(meterData[rowType], max) + "%");
	}

	/*
	 * Gauge methods
	 */
	function drawGauge(gaugeInfo) {
		var parentDiv = $("#" + gaugeInfo.divId);
		var html = "

" + gaugeInfo.title + "

";
		parentDiv.html(html);
	}
	function updateGauge(gaugeInfo, json) {
		var metricData = gaugeInfo.getMetricNode(gaugeInfo.className, gaugeInfo.metricName, json);
		if (metricData) {
			updateGaugeData(gaugeInfo, metricData);
		}
	}
	function updateGaugeData(gaugeInfo, gaugeData) {
		var gaugeDiv = $("#" + gaugeInfo.divId + " div.gaugeDataVal");
		gaugeDiv.html(gaugeData.value);
	}

	/*
	 * GaugeTable methods
	 */
	function drawGaugeTable(divId, title, gauges) {
		var parentDiv = $("#" + divId);
		var html = "
"
				+ "<fieldset><legend>
" + title + "
</legend>"
				+ "

</fieldset>
";

		parentDiv.html(html);
	}
	function updateGaugeTable(divId, gauges, json) {
		var div = $("#" + divId + " table");

		var html = "";
		var length = gauges.length;
		for (var i = 0; i < length; i++) {
			var gauge = gauges[i];
			html += "

" + gauge.title + "
	"
				+ "
" + gauge.getMetricNode(gauge.className, gauge.metricName, json).value
				+ "

";
		}
		div.html(html);
	}

	/*
	 * Cache methods
	 */
	function drawCache(cacheInfo) {
		var parentDiv = $("#" + cacheInfo.divId);

		var html = "
"
				+ "<fieldset><legend>
" + cacheInfo.title + "
</legend>"
				+ "
"
				+ "
"
				+ "

"
				+ "
"
				+ "

"
				+ "

"
				+ "
"
				+ "
"
				+ "
</fieldset>
";
		parentDiv.html(html);

		var length = cacheInfo.components.gauges.length;
		for (var i = 0; i < length; i++) {
			drawGauge(cacheInfo.components.gauges[i]);
		}
		drawTimer(cacheInfo.getTimer);
		drawTimer(cacheInfo.putTimer);
		drawGaugeTable(cacheInfo.divId + "Statistics", "Statistics", cacheInfo.components.gauges);
	}
	function updateCache(cacheInfo, json) {
		var length = cacheInfo.components.gauges.length;
		for (var i = 0; i < length; i++) {
			var gauge = cacheInfo.components.gauges[i];
			var data = gauge.getMetricNode(cacheInfo.className, gauge.metricName, json);
			if (data) {
				var gaugeDiv = $("#" + gauge.divId + " div.metricGraph div.gaugeDataVal");
				gaugeDiv.html(data.value);
			}
		}
		updateTimer(cacheInfo.getTimer, json);
		updateTimer(cacheInfo.putTimer, json);
		updateGaugeTable(cacheInfo.divId + "Statistics", cacheInfo.components.gauges, json);
	}

	/*
	 * JVM methods
	 */
	function drawJvm(jvmInfo) {
		var parentDiv = $("#" + jvmInfo.divId);
		var html = "
"
				+ "<fieldset><legend>
" + jvmInfo.title + "
</legend>"
				+ "
"
				+ "

"
				+ "
"
				+ "</fieldset>
";
		parentDiv.html(html);
	}

	function updateJvm(jvmInfo, json) {
		var vmDiv = $("#" + jvmInfo.divId + "Vm");
		var jvm = json['gauges'];
		var html = "
"
				+ "

Memory
"
				+ "

Total Init
	" + jvm['jvm.memory.total.init'].value + "
"
				+ "

Total Used
	" + jvm['jvm.memory.total.used'].value + "
"
				+ "

Total Max
	" + jvm['jvm.memory.total.max'].value + "
"
				+ "

Total Committed
	" + jvm['jvm.memory.total.committed'].value + "
"
				+ "

Heap Init
	" + jvm['jvm.memory.heap.init'].value + "
"
				+ "

Heap Used
	" + jvm['jvm.memory.heap.used'].value + "
"
				+ "

Heap Max
	" + jvm['jvm.memory.heap.max'].value + "
"
				+ "

Heap Committed
	" + jvm['jvm.memory.heap.committed'].value + "
"
				+ "

Non Heap Init
	" + jvm['jvm.memory.non-heap.init'].value + "
"
				+ "

Non Heap Used
	" + jvm['jvm.memory.non-heap.used'].value + "
"
				+ "

Non Heap Max
	" + jvm['jvm.memory.non-heap.max'].value + "
"
				+ "

Non Heap Committed
	" + jvm['jvm.memory.non-heap.committed'].value + "
"
				+ "

"
				+ "

Memory Usage
"
				+ "

Heap Usage
	" + (jvm['jvm.memory.heap.usage'].value * 100).toFixed(2) + "
"
				+ "

Non Heap Usage
	" + (jvm['jvm.memory.non-heap.usage'].value * 100).toFixed(2) + "
"
				+ (!jvm['jvm.memory.pools.JIT-code-cache.usage']?"":("

JIT Code Cache Usage
	" + (jvm['jvm.memory.pools.JIT-code-cache.usage'].value * 100).toFixed(2) + "
"))
				+ (!jvm['jvm.memory.pools.Code-Cache.usage']?"":("

JIT Code Cache Usage
	" + (jvm['jvm.memory.pools.Code-Cache.usage'].value * 100).toFixed(2) + "
"))
				+ (!jvm['jvm.memory.pools.JIT-data-cache.usage']?"":("

JIT Data Cache Usage
	" + (jvm['jvm.memory.pools.JIT-data-cache.usage'].value * 100).toFixed(2) + "
"))
				+ (!jvm['jvm.memory.pools.Java-heap.usage']?"":("

Java Heap Usage
	" + (jvm['jvm.memory.pools.Java-heap.usage'].value * 100).toFixed(2) + "
"))
				+ (!jvm['jvm.memory.pools.class-storage.usage']?"":("

Class Storage Usage
	" + (jvm['jvm.memory.pools.class-storage.usage'].value * 100).toFixed(2) + "
"))
				+ (!jvm['jvm.memory.pools.Perm-Gen.usage']?"":("

Perm Gen Usage
	" + (jvm['jvm.memory.pools.Perm-Gen.usage'].value * 100).toFixed(2) + "
"))
				+ (!jvm['jvm.memory.pools.Tenured-Gen.usage']?"":("

Tenured Gen Usage
	" + (jvm['jvm.memory.pools.Tenured-Gen.usage'].value * 100).toFixed(2) + "
"))
				+ (!jvm['jvm.memory.pools.miscellaneous-non-heap-storage.usage']?"":("

Misc Non Heap Storage Usage
	" + (jvm['jvm.memory.pools.miscellaneous-non-heap-storage.usage'].value * 100).toFixed(2)  + "
"))
				+ (!jvm['jvm.memory.pools.Survivor-Space.usage']?"":("

Survivor Space Usage
	" + (jvm['jvm.memory.pools.Survivor-Space.usage'].value * 100).toFixed(2) + "
"))
				+ (!jvm['jvm.memory.pools.Eden-Space.usage']?"":("

Eden Space Usage
	" + (jvm['jvm.memory.pools.Eden-Space.usage'].value * 100).toFixed(2) + "
"))
				+"

"
				+ "

Garbage Collection
"
				+ "

PS Mark Sweep Runs
	" + jvm['jvm.gc.MarkSweepCompact.count'].value + "
"
				+ "

PS Mark Sweep Time
	" + jvm['jvm.gc.MarkSweepCompact.time'].value + "
"
				+ "

GC Copy Runs
	" + jvm['jvm.gc.Copy.count'].value + "
"
				+ "

GC Copy Time
	" + jvm['jvm.gc.Copy.time'].value + "
"
				+ "

"
				+ "

Threads
"
//				+ "

Name
	" + jvm['jvm.vm.name'].value + "
"
//				+ "

Version
	" + jvm['jvm.vm.version'].value + "
"
//				+ "

Current Time
	" + jvm['jvm.current_time'].value + "
"
//				+ "

Uptime
	" + jvm['jvm.uptime'].value + "
"
				+ "

FD Usage
	" + formatNumber(jvm['jvm.fd.usage'].value, 2) + "
"
				+ "

Daemon Threads
	" + jvm['jvm.thread-states.daemon.count'].value + "
"
				+ "

Threads
	" + jvm['jvm.thread-states.count'].value + "
"
				+ "

Deadlocks
	" + jvm['jvm.thread-states.deadlocks'].value + "
"
				+ "

Thread States
"
				+ "

Terminated
	" + jvm['jvm.thread-states.terminated.count'].value + "
"
				+ "

Timed Waiting
	" + jvm['jvm.thread-states.timed_waiting.count'].value + "
"
				+ "

Blocked
	" + jvm['jvm.thread-states.blocked.count'].value + "
"
				+ "

Waiting
	" + jvm['jvm.thread-states.waiting.count'].value + "
"
				+ "

Runnable
	" + jvm['jvm.thread-states.runnable.count'].value + "
"
				+ "

New
	" + jvm['jvm.thread-states.new.count'].value + "
"
				+ "

";

		vmDiv.html(html);
	};

	/*
	 * Web Server methods
	 */
	function drawWeb(webInfo) {
		var parentDiv = $("#" + webInfo.divId);
		var html = "
"
				+ "<fieldset><legend>
" + webInfo.title + "
</legend>"
				+ "
"
				+ "

"
				+ "

"
				+ "	"
				+ "

"
				+ "	"
				+ "	"
				+ "	"
				+ "	"
				+ "

"
				+ "	"
				+ "	"
				+ "	"
				+ "	"
				+ "

"
				+ "
"
				+ "</fieldset>
";
		parentDiv.html(html);

		drawTimer(webInfo.components.requestsInfo);
		drawCounter(webInfo.components.activeRequestsInfo);

		var length = webInfo.components.meters.length;
		for (var i = 0; i < length; i++) {
			drawMeter(webInfo.components.meters[i]);
		}
	};

	function updateWeb(webInfo, json) {
		updateTimer(webInfo.components.requestsInfo, json);
		updateCounter(webInfo.components.activeRequestsInfo, json);

		var length = webInfo.components.meters.length;
		for (var i = 0; i < length; i++) {
			updateMeter(webInfo.components.meters[i], json);
		}
	};

	/*
	 * Log4j events stream  methods
	 */
	function drawLog4j(log4jInfo) {
		var parentDiv = $("#" + log4jInfo.divId);
		var html = "
"
				+ "<fieldset><legend>
" + log4jInfo.title + "
</legend>"
				+ "
"
				+ "

"
				+ "

"
				+ "	"
				+ "

"
				+ "	"
				+ "	"
				+ "	"
				+ "	"
				+ "

"
				+ "	"
				+ "	"
				+ "	"
				+ "

"
				+ "
"
				+ "</fieldset>
";
		parentDiv.html(html);

		var length = log4jInfo.components.meters.length;
		for (var i = 0; i < length; i++) {
			drawMeter(log4jInfo.components.meters[i]);
		}
	};

	function updateLog4j(log4jInfo, json) {
		var length = log4jInfo.components.meters.length;
		for (var i = 0; i < length; i++) {
			updateMeter(log4jInfo.components.meters[i], json);
		}
	};

}(window.metricsWatcher = window.metricsWatcher || {}, jQuery));


text:
layout: kanji
v4: 1287
v6: 1381
kanji: 踏
keyword: step
elements: step, wooden leg, mouth, stop, footprint, wednesday, boots, water, sun, day
strokes: 15
image: E8B88F
on-yomi: トウ
kun-yomi: ふ.む、ふ.まえる
permalink: /rtk/踏/
prev: 践
next: 踪
---

1) [trikatu] 28-2-2007(219): You have to watch your step when moving your leg on a watery day.

2) [smithsonian] 16-5-2007(80): So, we've walked on the moon, but it's going to take a pirate with a wooden leg, with a huge supply of cooling water to land on the sun and take that "one small step for a man".

3) [wazato] 5-11-2007(47): Use Floatingweed5's story, except, to remember the positioning of water and sun, picture the pirate pouring water into his mouth with a wagging tongue. How refreshing while doing his step aerobics.

4) [Floatingweed5] 10-10-2007(44): The peg leg pirate, wanting to get fit, signs up for some step aerobic classes. Here is is clutching his bottle of water and stepping up and down from his step platform in the island sunshine.

5) [herman] 23-11-2008(36): This is better remembered as "step on" or trample. I picture a puddle of water with the sun reflected in it (to get the water above sun positioning), then you step on the puddle with your foot to trample the image.

redpajama_set_name: RedPajamaGithub


text:
package org.apache.isis.viewer.restfulobjects.applib.domainobjects;

import com.fasterxml.jackson.databind.JsonNode;
import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;

public class ObjectCollectionRepresentation extends AbstractObjectMemberRepresentation {

    public ObjectCollectionRepresentation(final JsonNode jsonNode) {
        super(jsonNode);
    }

    public JsonRepresentation getValue() {
        return getArray("value").ensureArray();
    }

}


text:
import pytest

from pyscaffold import api
from pyscaffold.api import helpers
from pyscaffold.exceptions import ActionNotFound
from pyscaffold.structure import define_structure

def test_merge_basics():
    # Given an existing structure,
    structure = {"a": {"b": {"c": "1",
                             "d": "2"}}}
    # when it is merged to another structure with some common folder
    extra_files = {"a": {"b": {"c": "0"},
                         "e": "2"},
                   "f": {"g": {"h": "0"}}}
    structure = helpers.merge(structure, extra_files)
    # then the result, should contain both files from the original and the
    # merged structure,
    assert structure["a"]["b"]["d"] == "2"
    assert structure["f"]["g"]["h"] == "0"
    assert structure["a"]["e"] == "2"
    # the common leaves should be overridden and a tuple (content, rule)
    assert structure["a"]["b"]["c"] == "0"

def test_merge_rules_just_in_original():
    # When an update rule exists in the original structure,
    structure = {"a": {"b": ("0", helpers.NO_CREATE)}}
    # but not in the merged,
    extra_files = {"a": {"b": "3"}}
    structure = helpers.merge(structure, extra_files)
    # then just the content should be updated
    # and the rule should be kept identical
    assert structure["a"]["b"] == ("3", helpers.NO_CREATE)

def test_merge_rules_just_in_merged():
    # When an update rule does not exist in the original structure,
    structure = {"a": {"b": "0"}}
    # but exists in the merged,
    extra_files = {"a": {"b": (None, helpers.NO_CREATE)}}
    structure = helpers.merge(structure, extra_files)
    # then just the rule should be updated
    # and the content should be kept identical
    assert structure["a"]["b"] == ("0", helpers.NO_CREATE)

def test_empty_string_leads_to_empty_file_during_merge():
    # When the original structure contains a leaf,
    structure = {"a": {"b": "0"}}
    # and the merged structure overrides it with an empty content
    extra_files = {"a": {"b": ""}}
    structure = helpers.merge(structure, extra_files)
    # then the resulting content should exist and be empty
    assert structure["a"]["b"] == ""

def test_ensure_nested():
    # When the original structure does not contain a leaf
    structure = {"a": {"b": "0"}}
    # that is added using the ensure method,
    structure = helpers.ensure(structure,
                               ["a", "c", "d", "e", "f"], content="1")
    # then all the necessary parent folder should be included
    assert isinstance(structure["a"]["c"], dict)
    assert isinstance(structure["a"]["c"]["d"], dict)
    assert isinstance(structure["a"]["c"]["d"]["e"], dict)
    # and the file itself
    assert structure["a"]["c"]["d"]["e"]["f"] == "1"

def test_ensure_overriden():
    # When the original structure contains a leaf
    structure = {"a": {"b": "0"}}
    # that is overridden using the ensure method,
    structure = helpers.ensure(structure, ["a", "b"], content="1")
    # and the file content should be overridden
    assert structure["a"]["b"] == "1"

def test_ensure_path():
    # When the ensure method is called with an string path
    structure = {}
    structure = helpers.ensure(structure, "a/b/c/d", content="1")
    # Then the effect should be the same as if it were split
    assert structure["a"]["b"]["c"]["d"] == "1"

def test_reject():
    # When the original structure contain a leaf
    structure = {"a": {"b": {"c": "0"}}}
    # that is removed using the reject method,
    structure = helpers.reject(structure, ["a", "b", "c"])
    # then the structure should not contain the file
    assert "c" not in structure["a"]["b"]

def test_reject_without_ancestor():
    # Given a defined structure,
    structure = {"a": {"b": {"c": "0"}}}
    # when someone tries to remove a file using the reject method
    # but one of its ancestor does not exist in the structure,
    structure = helpers.reject(structure, "a/b/x/c")
    # then the structure should be the same
    assert structure["a"]["b"]["c"] == "0"
    assert len(structure["a"]["b"]["c"]) == 1
    assert len(structure["a"]["b"]) == 1
    assert len(structure["a"]) == 1

def test_reject_without_file():
    # Given a defined structure,
    structure = {"a": {"b": {"c": "0"}}}
    # when someone tries to remove a file using the reject method
    # but one of its ancestor does not exist in the structure,
    structure = helpers.reject(structure, "a/b/x")
    # then the structure should be the same
    assert structure["a"]["b"]["c"] == "0"
    assert len(structure["a"]["b"]["c"]) == 1
    assert len(structure["a"]["b"]) == 1
    assert len(structure["a"]) == 1

def custom_action(structure, options):
    return (structure, options)

custom_action.__module__ = 'awesome_module'

def init_git(structure, options):
    """Fake action that shares the same name as a default action."""
    return (structure, options)

def test_get_id():
    assert helpers.get_id(custom_action) == 'awesome_module:custom_action'

def test_register_before():
    # Given an action list,
    actions = [api.init_git]
    # When a new action is registered before another, using the function name
    # as position reference,
    actions = helpers.register(actions, custom_action, before='init_git')
    # Then this action should be correctly placed
    assert actions == [custom_action, api.init_git]

def test_register_after():
    # Given an action list,
    actions = [api.init_git]
    # When a new action is registered after another, using the function name
    # as position reference,
    actions = helpers.register(actions, custom_action, after='init_git')
    # Then this action should be correctly placed
    assert actions == [api.init_git, custom_action]

def test_register_with_qualified_name():
    # Given an action list with actions that share the same name,
    actions = [api.init_git, init_git]
    # When a new action is registered using the "qualified" name
    # (module+function) as position reference,
    actions = helpers.register(actions, custom_action,
                               after='pyscaffold.api:init_git')
    # Then this action should be correctly placed
    assert actions == [api.init_git, custom_action, init_git]

def test_register_default_position():
    # Given an action list with define_structure,
    actions = [api.init_git, define_structure, init_git]
    # When a new action is registered without position reference,
    actions = helpers.register(actions, custom_action)
    # Then this action should be placed after define_structure
    assert actions == [api.init_git, define_structure, custom_action, init_git]

def test_register_with_invalid_reference():
    # Given an action list,
    actions = [api.init_git]
    # When a new action is registered using an invalid reference,
    with pytest.raises(ActionNotFound):
        # Then the proper exception should be raised,
        actions = helpers.register(actions, custom_action,
                                   after='undefined_action')
    # And the action list should remain the same
    assert actions == [api.init_git]

def test_unregister():
    # Given an action list with name conflict,
    actions = [custom_action, init_git, api.init_git]
    # When an action is unregistered by name,
    actions = helpers.unregister(actions, 'init_git')
    # Then the first match should be removed
    assert actions == [custom_action, api.init_git]

def test_unregister_with_qualified_name():
    # Given an action list with name conflict,
    actions = [custom_action, init_git, api.init_git]
    # When an action is unregistered by "qualified" name,
    actions = helpers.unregister(actions, 'pyscaffold.api:init_git')
    # Then the correct match should be removed
    assert actions == [custom_action, init_git]

def test_unregister_with_undefined_action():
    # Given an action list,
    actions = [api.init_git]
    # When a undefined action is unregistered,
    with pytest.raises(ActionNotFound):
        # Then the proper exception should be raised,
        actions = helpers.unregister(actions, 'undefined_action')
    # And the action list should remain the same
    assert actions == [api.init_git]

def f(a, b, c):
    """Example that change the result if arguments switch order."""
    return (a**2)/(b - c)


text:
"""
Definition of the :class:`EnsureSize` interface.
"""
from os import path as op

import nibabel as nib
import numpy as np
from mriqc import config, messages
from nipype.interfaces.ants import ApplyTransforms
from nipype.interfaces.base import (
    BaseInterfaceInputSpec,
    File,
    SimpleInterface,
    TraitedSpec,
    isdefined,
    traits,
)
from pkg_resources import resource_filename as pkgrf

OUT_FILE_NAME = "{prefix}_resampled{ext}"
OUT_MASK_NAME = "{prefix}_resmask{ext}"
REF_FILE_NAME = "resample_ref.nii.gz"
REF_MASK_NAME = "mask_ref.nii.gz"

class EnsureSizeInputSpec(BaseInterfaceInputSpec):
    """
    Input specification for the :class:`EnsureSize` interface.
    """

    in_file = File(exists=True, copyfile=False, mandatory=True, desc="input image")
    in_mask = File(exists=True, copyfile=False, desc="input mask")
    pixel_size = traits.Float(2.0, usedefault=True, desc="desired pixel size (mm)")

class EnsureSizeOutputSpec(TraitedSpec):
    """
    Output specification for the :class:`EnsureSize` interface.
    """

    out_file = File(exists=True, desc="output image")
    out_mask = File(exists=True, desc="output mask")

class EnsureSize(SimpleInterface):
    """
    Checks the size of the input image and resamples it to have `pixel_size`.
    """

    input_spec = EnsureSizeInputSpec
    output_spec = EnsureSizeOutputSpec

    def _check_size(self, nii: nib.Nifti1Image) -> bool:
        zooms = nii.header.get_zooms()
        size_diff = np.array(zooms[:3]) - (self.inputs.pixel_size - 0.1)
        if np.all(size_diff >= -1e-3):
            config.loggers.interface.info(messages.VOXEL_SIZE_OK)
            return True
        else:
            small_voxel_message = messages.VOXEL_SIZE_SMALL.format(
                *zooms[:3], self.inputs.pixel_size, *size_diff
            )
            config.loggers.interface.info(small_voxel_message)
            return False

    def _run_interface(self, runtime):
        nii = nib.load(self.inputs.in_file)
        size_ok = self._check_size(nii)
        if size_ok:
            self._results["out_file"] = self.inputs.in_file
            if isdefined(self.inputs.in_mask):
                self._results["out_mask"] = self.inputs.in_mask
        else:
            # Figure out new matrix
            # 1) Get base affine
            aff_base = nii.header.get_base_affine()
            aff_base_inv = np.linalg.inv(aff_base)

            # 2) Find center pixel in mm
            center_idx = (np.array(nii.shape[:3]) - 1) * 0.5
            center_mm = aff_base.dot(center_idx.tolist() + [1])

            # 3) Find extent of each dimension
            min_mm = aff_base.dot([-0.5, -0.5, -0.5, 1])
            max_mm = aff_base.dot((np.array(nii.shape[:3]) - 0.5).tolist() + [1])
            extent_mm = np.abs(max_mm - min_mm)[:3]

            # 4) Find new matrix size
            new_size = np.array(extent_mm / self.inputs.pixel_size, dtype=int)

            # 5) Initialize new base affine
            new_base = (
                aff_base[:3, :3] * np.abs(aff_base_inv[:3, :3]) * self.inputs.pixel_size
            )

            # 6) Find new center
            new_center_idx = (new_size - 1) * 0.5
            new_affine_base = np.eye(4)
            new_affine_base[:3, :3] = new_base
            new_affine_base[:3, 3] = center_mm[:3] - new_base.dot(new_center_idx)

            # 7) Rotate new matrix
            rotation = nii.affine.dot(aff_base_inv)
            new_affine = rotation.dot(new_affine_base)

            # 8) Generate new reference image
            hdr = nii.header.copy()
            hdr.set_data_shape(new_size)
            nib.Nifti1Image(
                np.zeros(new_size, dtype=nii.get_data_dtype()), new_affine, hdr
            ).to_filename(REF_FILE_NAME)

            out_prefix, ext = op.splitext(op.basename(self.inputs.in_file))
            if ext == ".gz":
                out_prefix, ext2 = op.splitext(out_prefix)
                ext = ext2 + ext

            out_file_name = OUT_FILE_NAME.format(prefix=out_prefix, ext=ext)
            out_file = op.abspath(out_file_name)

            # 9) Resample new image
            ApplyTransforms(
                dimension=3,
                input_image=self.inputs.in_file,
                reference_image=REF_FILE_NAME,
                interpolation="LanczosWindowedSinc",
                transforms=[pkgrf("mriqc", "data/itk_identity.tfm")],
                output_image=out_file,
            ).run()

            self._results["out_file"] = out_file

            if isdefined(self.inputs.in_mask):
                hdr = nii.header.copy()
                hdr.set_data_shape(new_size)
                hdr.set_data_dtype(np.uint8)
                nib.Nifti1Image(
                    np.zeros(new_size, dtype=np.uint8), new_affine, hdr
                ).to_filename(REF_MASK_NAME)

                out_mask_name = OUT_MASK_NAME.format(prefix=out_prefix, ext=ext)
                out_mask = op.abspath(out_mask_name)
                ApplyTransforms(
                    dimension=3,
                    input_image=self.inputs.in_mask,
                    reference_image=REF_MASK_NAME,
                    interpolation="NearestNeighbor",
                    transforms=[pkgrf("mriqc", "data/itk_identity.tfm")],
                    output_image=out_mask,
                ).run()

                self._results["out_mask"] = out_mask

        return runtime


text:
package org.schors.vertx.telegram.bot.api.types.inline;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.schors.vertx.telegram.bot.api.types.InputMessageContent;

public class InlineQueryResultMpeg4Gif extends InlineQueryResult {
    private Type type;
    private String id;
    @JsonProperty("mpeg4_url")
    private String mpeg4Url;
    @JsonProperty("mpeg4_width")
    private Integer mpeg4Width;
    @JsonProperty("mpeg4_height")
    private Integer mpeg4Height;
    @JsonProperty("mpeg4_duration")
    private Integer mpeg4Duration;
    @JsonProperty("thumb_url")
    private String thumbUrl;
    private String title;
    private String caption;
    @JsonProperty("reply_markup")
    private InlineKeyboardMarkup replyMarkup;
    @JsonProperty("input_message_content")
    private InputMessageContent inputMessageContent;

    public InlineQueryResultMpeg4Gif() {
        this.type = Type.mpeg4_gif;
    }

    public InlineQueryResultMpeg4Gif(Type type, String id, String mpeg4Url, Integer mpeg4Width, Integer mpeg4Height, String thumbUrl, String title, String caption, InlineKeyboardMarkup replyMarkup, InputMessageContent inputMessageContent) {
        this.type = type;
        this.id = id;
        this.mpeg4Url = mpeg4Url;
        this.mpeg4Width = mpeg4Width;
        this.mpeg4Height = mpeg4Height;
        this.thumbUrl = thumbUrl;
        this.title = title;
        this.caption = caption;
        this.replyMarkup = replyMarkup;
        this.inputMessageContent = inputMessageContent;
    }

    public Type getType() {
        return type;
    }

    public InlineQueryResultMpeg4Gif setType(Type type) {
        this.type = type;
        return this;
    }

    public String getId() {
        return id;
    }

    public InlineQueryResultMpeg4Gif setId(String id) {
        this.id = id;
        return this;
    }

    public String getMpeg4Url() {
        return mpeg4Url;
    }

    public InlineQueryResultMpeg4Gif setMpeg4Url(String mpeg4Url) {
        this.mpeg4Url = mpeg4Url;
        return this;
    }

    public Integer getMpeg4Width() {
        return mpeg4Width;
    }

    public InlineQueryResultMpeg4Gif setMpeg4Width(Integer mpeg4Width) {
        this.mpeg4Width = mpeg4Width;
        return this;
    }

    public Integer getMpeg4Height() {
        return mpeg4Height;
    }

    public InlineQueryResultMpeg4Gif setMpeg4Height(Integer mpeg4Height) {
        this.mpeg4Height = mpeg4Height;
        return this;
    }

    public String getThumbUrl() {
        return thumbUrl;
    }

    public InlineQueryResultMpeg4Gif setThumbUrl(String thumbUrl) {
        this.thumbUrl = thumbUrl;
        return this;
    }

    public String getTitle() {
        return title;
    }

    public InlineQueryResultMpeg4Gif setTitle(String title) {
        this.title = title;
        return this;
    }

    public String getCaption() {
        return caption;
    }

    public InlineQueryResultMpeg4Gif setCaption(String caption) {
        this.caption = caption;
        return this;
    }

    public InlineKeyboardMarkup getReplyMarkup() {
        return replyMarkup;
    }

    public InlineQueryResultMpeg4Gif setReplyMarkup(InlineKeyboardMarkup replyMarkup) {
        this.replyMarkup = replyMarkup;
        return this;
    }

    public InputMessageContent getInputMessageContent() {
        return inputMessageContent;
    }

    public InlineQueryResultMpeg4Gif setInputMessageContent(InputMessageContent inputMessageContent) {
        this.inputMessageContent = inputMessageContent;
        return this;
    }

    public Integer getMpeg4Duration() {
        return mpeg4Duration;
    }

    public InlineQueryResultMpeg4Gif setMpeg4Duration(Integer mpeg4Duration) {
        this.mpeg4Duration = mpeg4Duration;
        return this;
    }
}


text:
namespace ContosoUniversity.IntegrationTests.Features.Departments
{
    using System;
    using Microsoft.EntityFrameworkCore;
    using System.Linq;
    using System.Threading.Tasks;
    using ContosoUniversity.Features.Departments;
    using Models;
    using Shouldly;
    using Xunit;
    using static SliceFixture;

    public class CreateTests : IntegrationTestBase
    {
        [Fact]
        public async Task Should_create_new_department()
        {
            var adminId = await SendAsync(new ContosoUniversity.Features.Instructors.CreateEdit.Command
            {
                FirstMidName = "George",
                LastName = "Costanza",
                HireDate = DateTime.Today,
            });

            Create.Command command = null;

            await ExecuteDbContextAsync(async (db, mediator) =>
            {
                var admin = await db.Instructors.FindAsync(adminId);

                command = new Create.Command
                {
                    Budget = 10m,
                    Name = "Engineering",
                    StartDate = DateTime.Now.Date,
                    Administrator = admin
                };

                await mediator.Send(command);
            });

            var created = await ExecuteDbContextAsync(db => db.Departments.Where(d => d.Name == command.Name).SingleOrDefaultAsync());

            created.ShouldNotBeNull();
            created.Budget.ShouldBe(command.Budget.GetValueOrDefault());
            created.StartDate.ShouldBe(command.StartDate.GetValueOrDefault());
            created.InstructorID.ShouldBe(adminId);
        }
    }
}


text:
#pragma once

/*! \file cusp/system/cuda/execution_policy.h
 *  \brief Execution policies for CUSP's CUDA system.
 */

#include <thrust/detail/config.h>

// get the execution policies definitions first
#include <thrust/system/cuda/detail/execution_policy.h>

// get the definition of par
#include <thrust/system/cuda/detail/par.h>

#if THRUST_VERSION < 100800
#include <cusp/detail/thrust/system/cuda/detail/execute_on_stream.h>
#endif

// now get all the algorithm definitions

#include <cusp/system/cuda/detail/blas.h>
#include <cusp/system/cuda/detail/convert.h>
#include <cusp/system/cuda/detail/copy.h>
#include <cusp/system/cuda/detail/elementwise.h>
#include <cusp/system/cuda/detail/format_utils.h>
#include <cusp/system/cuda/detail/multiply.h>
#include <cusp/system/cuda/detail/sort.h>
#include <cusp/system/cuda/detail/transpose.h>

#include <cusp/system/cuda/detail/graph/breadth_first_search.h>
#include <cusp/system/cuda/detail/graph/connected_components.h>
#include <cusp/system/cuda/detail/graph/hilbert_curve.h>
#include <cusp/system/cuda/detail/graph/maximal_independent_set.h>
#include <cusp/system/cuda/detail/graph/pseudo_peripheral.h>
#include <cusp/system/cuda/detail/graph/symmetric_rcm.h>
#include <cusp/system/cuda/detail/graph/vertex_coloring.h>

#include <cusp/system/cuda/detail/relaxation/gauss_seidel.h>


text:
<?php
/**
 * Created by PhpStorm.
 * User: Kodemania
 * Date: 29/10/2015
 * Time: 9:59 PM
 */
    $this->load->view('admin/includes/head.php');
?>

            <?php $this->load->view('admin/includes/nav.php'); ?>

Add New Gallery

            <?php if(validation_errors()){
                ?>

                    <?php echo validation_errors(); ?>

            <?php
            } ?>
            <?php if($this->session->flashdata('error')){
                ?>

                    <?php echo $this->session->flashdata('error'); ?>

            <?php
            } ?>
            <?php echo form_open_multipart('admin/addGalleryProcess',array('class'=>"form-horizontal")); ?>

                Title

                    <input type="text" class="form-control" id="title" placeholder="Gallery Title" name="title">

                File input

                    <input type="file" id="InputFile" name="userFile">

Required

                    <button type="submit" class="btn btn-primary">Add New Gallery</button>

            </form>


text:
package com.google.android.exoplayer2.ext.ima;

import android.content.Context;
import android.net.Uri;
import android.os.SystemClock;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.ViewGroup;
import android.webkit.WebView;
import com.google.ads.interactivemedia.v3.api.Ad;
import com.google.ads.interactivemedia.v3.api.AdDisplayContainer;
import com.google.ads.interactivemedia.v3.api.AdError;
import com.google.ads.interactivemedia.v3.api.AdError.AdErrorCode;
import com.google.ads.interactivemedia.v3.api.AdErrorEvent;
import com.google.ads.interactivemedia.v3.api.AdErrorEvent.AdErrorListener;
import com.google.ads.interactivemedia.v3.api.AdEvent;
import com.google.ads.interactivemedia.v3.api.AdEvent.AdEventListener;
import com.google.ads.interactivemedia.v3.api.AdEvent.AdEventType;
import com.google.ads.interactivemedia.v3.api.AdPodInfo;
import com.google.ads.interactivemedia.v3.api.AdsLoader.AdsLoadedListener;
import com.google.ads.interactivemedia.v3.api.AdsManager;
import com.google.ads.interactivemedia.v3.api.AdsManagerLoadedEvent;
import com.google.ads.interactivemedia.v3.api.AdsRenderingSettings;
import com.google.ads.interactivemedia.v3.api.AdsRequest;
import com.google.ads.interactivemedia.v3.api.ImaSdkFactory;
import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;
import com.google.ads.interactivemedia.v3.api.player.ContentProgressProvider;
import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer;
import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
import com.google.android.exoplayer2.source.ads.AdPlaybackState.AdState;
import com.google.android.exoplayer2.source.ads.AdsLoader;
import com.google.android.exoplayer2.source.ads.AdsMediaSource.AdLoadException;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Loads ads using the IMA SDK. All methods are called on the main thread.
 */
public final class ImaAdsLoader extends Player.DefaultEventListener implements AdsLoader,
    VideoAdPlayer, ContentProgressProvider, AdErrorListener, AdsLoadedListener, AdEventListener {

  static {
    ExoPlayerLibraryInfo.registerModule("goog.exo.ima");
  }

  /** Builder for {@link ImaAdsLoader}. */
  public static final class Builder {

    private final Context context;

    private @Nullable ImaSdkSettings imaSdkSettings;
    private @Nullable AdEventListener adEventListener;
    private int vastLoadTimeoutMs;
    private int mediaLoadTimeoutMs;

    /**
     * Creates a new builder for {@link ImaAdsLoader}.
     *
     * @param context The context;
     */
    public Builder(Context context) {
      this.context = Assertions.checkNotNull(context);
      vastLoadTimeoutMs = TIMEOUT_UNSET;
      mediaLoadTimeoutMs = TIMEOUT_UNSET;
    }

    /**
     * Sets the IMA SDK settings. The provided settings instance's player type and version fields
     * may be overwritten.
     *
     *
If this method is not called the default settings will be used.
     *
     * @param imaSdkSettings The {@link ImaSdkSettings}.
     * @return This builder, for convenience.
     */
    public Builder setImaSdkSettings(ImaSdkSettings imaSdkSettings) {
      this.imaSdkSettings = Assertions.checkNotNull(imaSdkSettings);
      return this;
    }

    /**
     * Sets a listener for ad events that will be passed to {@link
     * AdsManager#addAdEventListener(AdEventListener)}.
     *
     * @param adEventListener The ad event listener.
     * @return This builder, for convenience.
     */
    public Builder setAdEventListener(AdEventListener adEventListener) {
      this.adEventListener = Assertions.checkNotNull(adEventListener);
      return this;
    }

    /**
     * Sets the VAST load timeout, in milliseconds.
     *
     * @param vastLoadTimeoutMs The VAST load timeout, in milliseconds.
     * @return This builder, for convenience.
     * @see AdsRequest#setVastLoadTimeout(float)
     */
    public Builder setVastLoadTimeoutMs(int vastLoadTimeoutMs) {
      Assertions.checkArgument(vastLoadTimeoutMs >= 0);
      this.vastLoadTimeoutMs = vastLoadTimeoutMs;
      return this;
    }

    /**
     * Sets the ad media load timeout, in milliseconds.
     *
     * @param mediaLoadTimeoutMs The ad media load timeout, in milliseconds.
     * @return This builder, for convenience.
     * @see AdsRenderingSettings#setLoadVideoTimeout(int)
     */
    public Builder setMediaLoadTimeoutMs(int mediaLoadTimeoutMs) {
      Assertions.checkArgument(mediaLoadTimeoutMs >= 0);
      this.mediaLoadTimeoutMs = mediaLoadTimeoutMs;
      return this;
    }

    /**
     * Returns a new {@link ImaAdsLoader} for the specified ad tag.
     *
     * @param adTagUri The URI of a compatible ad tag to load. See
     *     https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for
     *     information on compatible ad tags.
     * @return The new {@link ImaAdsLoader}.
     */
    public ImaAdsLoader buildForAdTag(Uri adTagUri) {
      return new ImaAdsLoader(
          context,
          adTagUri,
          imaSdkSettings,
          null,
          vastLoadTimeoutMs,
          mediaLoadTimeoutMs,
          adEventListener);
    }

    /**
     * Returns a new {@link ImaAdsLoader} with the specified sideloaded ads response.
     *
     * @param adsResponse The sideloaded VAST, VMAP, or ad rules response to be used instead of
     *     making a request via an ad tag URL.
     * @return The new {@link ImaAdsLoader}.
     */
    public ImaAdsLoader buildForAdsResponse(String adsResponse) {
      return new ImaAdsLoader(
          context,
          null,
          imaSdkSettings,
          adsResponse,
          vastLoadTimeoutMs,
          mediaLoadTimeoutMs,
          adEventListener);
    }
  }

  private static final boolean DEBUG = false;
  private static final String TAG = "ImaAdsLoader";

  /**
   * Whether to enable preloading of ads in {@link AdsRenderingSettings}.
   */
  private static final boolean ENABLE_PRELOADING = true;

  private static final String IMA_SDK_SETTINGS_PLAYER_TYPE = "google/exo.ext.ima";
  private static final String IMA_SDK_SETTINGS_PLAYER_VERSION = ExoPlayerLibraryInfo.VERSION;

  /** The value used in {@link VideoProgressUpdate}s to indicate an unset duration. */
  private static final long IMA_DURATION_UNSET = -1L;

  /**
   * Threshold before the end of content at which IMA is notified that content is complete if the
   * player buffers, in milliseconds.
   */
  private static final long END_OF_CONTENT_POSITION_THRESHOLD_MS = 5000;

  /** The maximum duration before an ad break that IMA may start preloading the next ad. */
  private static final long MAXIMUM_PRELOAD_DURATION_MS = 8000;

  /**
   * The "Skip ad" button rendered in the IMA WebView does not gain focus by default and cannot be
   * clicked via a keypress event. Workaround this issue by calling focus() on the HTML element in
   * the WebView directly when an ad starts. See [Internal: b/62371030].
   */
  private static final String FOCUS_SKIP_BUTTON_WORKAROUND_JS = "javascript:"
      + "try{ document.getElementsByClassName(\"videoAdUiSkipButton\")[0].focus(); } catch (e) {}";

  private static final int TIMEOUT_UNSET = -1;

  /** The state of ad playback. */
  @Retention(RetentionPolicy.SOURCE)
  @IntDef({IMA_AD_STATE_NONE, IMA_AD_STATE_PLAYING, IMA_AD_STATE_PAUSED})
  private @interface ImaAdState {}
  /**
   * The ad playback state when IMA is not playing an ad.
   */
  private static final int IMA_AD_STATE_NONE = 0;
  /**
   * The ad playback state when IMA has called {@link #playAd()} and not {@link #pauseAd()}.
   */
  private static final int IMA_AD_STATE_PLAYING = 1;
  /**
   * The ad playback state when IMA has called {@link #pauseAd()} while playing an ad.
   */
  private static final int IMA_AD_STATE_PAUSED = 2;

  private final @Nullable Uri adTagUri;
  private final @Nullable String adsResponse;
  private final int vastLoadTimeoutMs;
  private final int mediaLoadTimeoutMs;
  private final @Nullable AdEventListener adEventListener;
  private final Timeline.Period period;
  private final List<VideoAdPlayerCallback> adCallbacks;
  private final ImaSdkFactory imaSdkFactory;
  private final AdDisplayContainer adDisplayContainer;
  private final com.google.ads.interactivemedia.v3.api.AdsLoader adsLoader;

  private Object pendingAdRequestContext;
  private List<String> supportedMimeTypes;
  private EventListener eventListener;
  private Player player;
  private ViewGroup adUiViewGroup;
  private VideoProgressUpdate lastContentProgress;
  private VideoProgressUpdate lastAdProgress;

  private AdsManager adsManager;
  private AdLoadException pendingAdLoadError;
  private Timeline timeline;
  private long contentDurationMs;
  private int podIndexOffset;
  private AdPlaybackState adPlaybackState;

  // Fields tracking IMA's state.

  /** The expected ad group index that IMA should load next. */
  private int expectedAdGroupIndex;
  /**
   * The index of the current ad group that IMA is loading.
   */
  private int adGroupIndex;
  /**
   * Whether IMA has sent an ad event to pause content since the last resume content event.
   */
  private boolean imaPausedContent;
  /** The current ad playback state. */
  private @ImaAdState int imaAdState;
  /**
   * Whether {@link com.google.ads.interactivemedia.v3.api.AdsLoader#contentComplete()} has been
   * called since starting ad playback.
   */
  private boolean sentContentComplete;

  // Fields tracking the player/loader state.

  /**
   * Whether the player is playing an ad.
   */
  private boolean playingAd;
  /**
   * If the player is playing an ad, stores the ad index in its ad group. {@link C#INDEX_UNSET}
   * otherwise.
   */
  private int playingAdIndexInAdGroup;
  /**
   * Whether there's a pending ad preparation error which IMA needs to be notified of when it
   * transitions from playing content to playing the ad.
   */
  private boolean shouldNotifyAdPrepareError;
  /**
   * If a content period has finished but IMA has not yet called {@link #playAd()}, stores the value
   * of {@link SystemClock#elapsedRealtime()} when the content stopped playing. This can be used to
   * determine a fake, increasing content position. {@link C#TIME_UNSET} otherwise.
   */
  private long fakeContentProgressElapsedRealtimeMs;
  /**
   * If {@link #fakeContentProgressElapsedRealtimeMs} is set, stores the offset from which the
   * content progress should increase. {@link C#TIME_UNSET} otherwise.
   */
  private long fakeContentProgressOffsetMs;
  /**
   * Stores the pending content position when a seek operation was intercepted to play an ad.
   */
  private long pendingContentPositionMs;
  /**
   * Whether {@link #getContentProgress()} has sent {@link #pendingContentPositionMs} to IMA.
   */
  private boolean sentPendingContentPositionMs;

  /**
   * Creates a new IMA ads loader.
   *
   *
If you need to customize the ad request, use {@link ImaAdsLoader.Builder} instead.
   *
   * @param context The context.
   * @param adTagUri The {@link Uri} of an ad tag compatible with the Android IMA SDK. See
   *     https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for
   *     more information.
   */
  public ImaAdsLoader(Context context, Uri adTagUri) {
    this(
        context,
        adTagUri,
        /* imaSdkSettings= */ null,
        /* adsResponse= */ null,
        /* vastLoadTimeoutMs= */ TIMEOUT_UNSET,
        /* mediaLoadTimeoutMs= */ TIMEOUT_UNSET,
        /* adEventListener= */ null);
  }

  /**
   * Creates a new IMA ads loader.
   *
   * @param context The context.
   * @param adTagUri The {@link Uri} of an ad tag compatible with the Android IMA SDK. See
   *     https://developers.google.com/interactive-media-ads/docs/sdks/android/compatibility for
   *     more information.
   * @param imaSdkSettings {@link ImaSdkSettings} used to configure the IMA SDK, or {@code null} to
   *     use the default settings. If set, the player type and version fields may be overwritten.
   * @deprecated Use {@link ImaAdsLoader.Builder}.
   */
  @Deprecated
  public ImaAdsLoader(Context context, Uri adTagUri, ImaSdkSettings imaSdkSettings) {
    this(
        context,
        adTagUri,
        imaSdkSettings,
        /* adsResponse= */ null,
        /* vastLoadTimeoutMs= */ TIMEOUT_UNSET,
        /* mediaLoadTimeoutMs= */ TIMEOUT_UNSET,
        /* adEventListener= */ null);
  }

  private ImaAdsLoader(
      Context context,
      @Nullable Uri adTagUri,
      @Nullable ImaSdkSettings imaSdkSettings,
      @Nullable String adsResponse,
      int vastLoadTimeoutMs,
      int mediaLoadTimeoutMs,
      @Nullable AdEventListener adEventListener) {
    Assertions.checkArgument(adTagUri != null || adsResponse != null);
    this.adTagUri = adTagUri;
    this.adsResponse = adsResponse;
    this.vastLoadTimeoutMs = vastLoadTimeoutMs;
    this.mediaLoadTimeoutMs = mediaLoadTimeoutMs;
    this.adEventListener = adEventListener;
    period = new Timeline.Period();
    adCallbacks = new ArrayList<>(1);
    imaSdkFactory = ImaSdkFactory.getInstance();
    adDisplayContainer = imaSdkFactory.createAdDisplayContainer();
    adDisplayContainer.setPlayer(this);
    if (imaSdkSettings == null) {
      imaSdkSettings = imaSdkFactory.createImaSdkSettings();
    }
    imaSdkSettings.setPlayerType(IMA_SDK_SETTINGS_PLAYER_TYPE);
    imaSdkSettings.setPlayerVersion(IMA_SDK_SETTINGS_PLAYER_VERSION);
    adsLoader = imaSdkFactory.createAdsLoader(context, imaSdkSettings);
    adsLoader.addAdErrorListener(this);
    adsLoader.addAdsLoadedListener(this);
    fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET;
    fakeContentProgressOffsetMs = C.TIME_UNSET;
    pendingContentPositionMs = C.TIME_UNSET;
    adGroupIndex = C.INDEX_UNSET;
    contentDurationMs = C.TIME_UNSET;
  }

  /**
   * Returns the underlying {@code com.google.ads.interactivemedia.v3.api.AdsLoader} wrapped by
   * this instance.
   */
  public com.google.ads.interactivemedia.v3.api.AdsLoader getAdsLoader() {
    return adsLoader;
  }

  /**
   * Requests ads, if they have not already been requested. Must be called on the main thread.
   *
   *
Ads will be requested automatically when the player is prepared if this method has not been
   * called, so it is only necessary to call this method if you want to request ads before preparing
   * the player.
   *
   * @param adUiViewGroup A {@link ViewGroup} on top of the player that will show any ad UI.
   */
  public void requestAds(ViewGroup adUiViewGroup) {
    if (adPlaybackState != null || adsManager != null || pendingAdRequestContext != null) {
      // Ads have already been requested.
      return;
    }
    adDisplayContainer.setAdContainer(adUiViewGroup);
    pendingAdRequestContext = new Object();
    AdsRequest request = imaSdkFactory.createAdsRequest();
    if (adTagUri != null) {
      request.setAdTagUrl(adTagUri.toString());
    } else /* adsResponse != null */ {
      request.setAdsResponse(adsResponse);
    }
    if (vastLoadTimeoutMs != TIMEOUT_UNSET) {
      request.setVastLoadTimeout(vastLoadTimeoutMs);
    }
    request.setAdDisplayContainer(adDisplayContainer);
    request.setContentProgressProvider(this);
    request.setUserRequestContext(pendingAdRequestContext);
    adsLoader.requestAds(request);
  }

  // AdsLoader implementation.

  @Override
  public void setSupportedContentTypes(@C.ContentType int... contentTypes) {
    List<String> supportedMimeTypes = new ArrayList<>();
    for (@C.ContentType int contentType : contentTypes) {
      if (contentType == C.TYPE_DASH) {
        supportedMimeTypes.add(MimeTypes.APPLICATION_MPD);
      } else if (contentType == C.TYPE_HLS) {
        supportedMimeTypes.add(MimeTypes.APPLICATION_M3U8);
      } else if (contentType == C.TYPE_OTHER) {
        supportedMimeTypes.addAll(Arrays.asList(
            MimeTypes.VIDEO_MP4, MimeTypes.VIDEO_WEBM, MimeTypes.VIDEO_H263, MimeTypes.VIDEO_MPEG,
            MimeTypes.AUDIO_MP4, MimeTypes.AUDIO_MPEG));
      } else if (contentType == C.TYPE_SS) {
        // IMA does not support Smooth Streaming ad media.
      }
    }
    this.supportedMimeTypes = Collections.unmodifiableList(supportedMimeTypes);
  }

  @Override
  public void attachPlayer(ExoPlayer player, EventListener eventListener, ViewGroup adUiViewGroup) {
    this.player = player;
    this.eventListener = eventListener;
    this.adUiViewGroup = adUiViewGroup;
    lastAdProgress = null;
    lastContentProgress = null;
    adDisplayContainer.setAdContainer(adUiViewGroup);
    player.addListener(this);
    maybeNotifyPendingAdLoadError();
    if (adPlaybackState != null) {
      // Pass the ad playback state to the player, and resume ads if necessary.
      eventListener.onAdPlaybackState(adPlaybackState);
      if (imaPausedContent && player.getPlayWhenReady()) {
        adsManager.resume();
      }
    } else if (adsManager != null) {
      // Ads have loaded but the ads manager is not initialized.
      startAdPlayback();
    } else {
      // Ads haven't loaded yet, so request them.
      requestAds(adUiViewGroup);
    }
  }

  @Override
  public void detachPlayer() {
    if (adsManager != null && imaPausedContent) {
      adPlaybackState =
          adPlaybackState.withAdResumePositionUs(
              playingAd ? C.msToUs(player.getCurrentPosition()) : 0);
      adsManager.pause();
    }
    lastAdProgress = getAdProgress();
    lastContentProgress = getContentProgress();
    player.removeListener(this);
    player = null;
    eventListener = null;
    adUiViewGroup = null;
  }

  @Override
  public void release() {
    pendingAdRequestContext = null;
    if (adsManager != null) {
      adsManager.destroy();
      adsManager = null;
    }
  }

  @Override
  public void handlePrepareError(int adGroupIndex, int adIndexInAdGroup, IOException exception) {
    if (player == null) {
      return;
    }
    try {
      handleAdPrepareError(adGroupIndex, adIndexInAdGroup, exception);
    } catch (Exception e) {
      maybeNotifyInternalError("handlePrepareError", e);
    }
  }

  // com.google.ads.interactivemedia.v3.api.AdsLoader.AdsLoadedListener implementation.

  @Override
  public void onAdsManagerLoaded(AdsManagerLoadedEvent adsManagerLoadedEvent) {
    AdsManager adsManager = adsManagerLoadedEvent.getAdsManager();
    if (!Util.areEqual(pendingAdRequestContext, adsManagerLoadedEvent.getUserRequestContext())) {
      adsManager.destroy();
      return;
    }
    pendingAdRequestContext = null;
    this.adsManager = adsManager;
    adsManager.addAdErrorListener(this);
    adsManager.addAdEventListener(this);
    if (adEventListener != null) {
      adsManager.addAdEventListener(adEventListener);
    }
    if (player != null) {
      // If a player is attached already, start playback immediately.
      try {
        startAdPlayback();
      } catch (Exception e) {
        maybeNotifyInternalError("onAdsManagerLoaded", e);
      }
    }
  }

  // AdEvent.AdEventListener implementation.

  @Override
  public void onAdEvent(AdEvent adEvent) {
    AdEventType adEventType = adEvent.getType();
    if (DEBUG) {
      Log.d(TAG, "onAdEvent: " + adEventType);
    }
    if (adsManager == null) {
      Log.w(TAG, "Dropping ad event after release: " + adEvent);
      return;
    }
    try {
      handleAdEvent(adEvent);
    } catch (Exception e) {
      maybeNotifyInternalError("onAdEvent", e);
    }
  }

  // AdErrorEvent.AdErrorListener implementation.

  @Override
  public void onAdError(AdErrorEvent adErrorEvent) {
    AdError error = adErrorEvent.getError();
    if (DEBUG) {
      Log.d(TAG, "onAdError", error);
    }
    if (adsManager == null) {
      // No ads were loaded, so allow playback to start without any ads.
      pendingAdRequestContext = null;
      adPlaybackState = new AdPlaybackState();
      updateAdPlaybackState();
    } else if (isAdGroupLoadError(error)) {
      try {
        handleAdGroupLoadError(error);
      } catch (Exception e) {
        maybeNotifyInternalError("onAdError", e);
      }
    }
    if (pendingAdLoadError == null) {
      pendingAdLoadError = AdLoadException.createForAllAds(error);
    }
    maybeNotifyPendingAdLoadError();
  }

  // ContentProgressProvider implementation.

  @Override
  public VideoProgressUpdate getContentProgress() {
    if (player == null) {
      return lastContentProgress;
    }
    boolean hasContentDuration = contentDurationMs != C.TIME_UNSET;
    long contentPositionMs;
    if (pendingContentPositionMs != C.TIME_UNSET) {
      sentPendingContentPositionMs = true;
      contentPositionMs = pendingContentPositionMs;
      expectedAdGroupIndex =
          adPlaybackState.getAdGroupIndexForPositionUs(C.msToUs(contentPositionMs));
    } else if (fakeContentProgressElapsedRealtimeMs != C.TIME_UNSET) {
      long elapsedSinceEndMs = SystemClock.elapsedRealtime() - fakeContentProgressElapsedRealtimeMs;
      contentPositionMs = fakeContentProgressOffsetMs + elapsedSinceEndMs;
      expectedAdGroupIndex =
          adPlaybackState.getAdGroupIndexForPositionUs(C.msToUs(contentPositionMs));
    } else if (imaAdState == IMA_AD_STATE_NONE && !playingAd && hasContentDuration) {
      contentPositionMs = player.getCurrentPosition();
      // Update the expected ad group index for the current content position. The update is delayed
      // until MAXIMUM_PRELOAD_DURATION_MS before the ad so that an ad group load error delivered
      // just after an ad group isn't incorrectly attributed to the next ad group.
      int nextAdGroupIndex =
          adPlaybackState.getAdGroupIndexAfterPositionUs(C.msToUs(contentPositionMs));
      if (nextAdGroupIndex != expectedAdGroupIndex && nextAdGroupIndex != C.INDEX_UNSET) {
        long nextAdGroupTimeMs = C.usToMs(adPlaybackState.adGroupTimesUs[nextAdGroupIndex]);
        if (nextAdGroupTimeMs == C.TIME_END_OF_SOURCE) {
          nextAdGroupTimeMs = contentDurationMs;
        }
        if (nextAdGroupTimeMs - contentPositionMs < MAXIMUM_PRELOAD_DURATION_MS) {
          expectedAdGroupIndex = nextAdGroupIndex;
        }
      }
    } else {
      return VideoProgressUpdate.VIDEO_TIME_NOT_READY;
    }
    long contentDurationMs = hasContentDuration ? this.contentDurationMs : IMA_DURATION_UNSET;
    return new VideoProgressUpdate(contentPositionMs, contentDurationMs);
  }

  // VideoAdPlayer implementation.

  @Override
  public VideoProgressUpdate getAdProgress() {
    if (player == null) {
      return lastAdProgress;
    } else if (imaAdState != IMA_AD_STATE_NONE && playingAd) {
      long adDuration = player.getDuration();
      return adDuration == C.TIME_UNSET ? VideoProgressUpdate.VIDEO_TIME_NOT_READY
          : new VideoProgressUpdate(player.getCurrentPosition(), adDuration);
    } else {
      return VideoProgressUpdate.VIDEO_TIME_NOT_READY;
    }
  }

  @Override
  public void loadAd(String adUriString) {
    try {
      if (adGroupIndex == C.INDEX_UNSET) {
        Log.w(
            TAG,
            "Unexpected loadAd without LOADED event; assuming ad group index is actually "
                + expectedAdGroupIndex);
        adGroupIndex = expectedAdGroupIndex;
        adsManager.start();
      }
      if (DEBUG) {
        Log.d(TAG, "loadAd in ad group " + adGroupIndex);
      }
      int adIndexInAdGroup = getAdIndexInAdGroupToLoad(adGroupIndex);
      if (adIndexInAdGroup == C.INDEX_UNSET) {
        Log.w(TAG, "Unexpected loadAd in an ad group with no remaining unavailable ads");
        return;
      }
      adPlaybackState =
          adPlaybackState.withAdUri(adGroupIndex, adIndexInAdGroup, Uri.parse(adUriString));
      updateAdPlaybackState();
    } catch (Exception e) {
      maybeNotifyInternalError("loadAd", e);
    }
  }

  @Override
  public void addCallback(VideoAdPlayerCallback videoAdPlayerCallback) {
    adCallbacks.add(videoAdPlayerCallback);
  }

  @Override
  public void removeCallback(VideoAdPlayerCallback videoAdPlayerCallback) {
    adCallbacks.remove(videoAdPlayerCallback);
  }

  @Override
  public void playAd() {
    if (DEBUG) {
      Log.d(TAG, "playAd");
    }
    switch (imaAdState) {
      case IMA_AD_STATE_PLAYING:
        // IMA does not always call stopAd before resuming content.
        // See [Internal: b/38354028, b/63320878].
        Log.w(TAG, "Unexpected playAd without stopAd");
        break;
      case IMA_AD_STATE_NONE:
        // IMA is requesting to play the ad, so stop faking the content position.
        fakeContentProgressElapsedRealtimeMs = C.TIME_UNSET;
        fakeContentProgressOffsetMs = C.TIME_UNSET;
        imaAdState = IMA_AD_STATE_PLAYING;
        for (int i = 0; i < adCallbacks.size(); i++) {
          adCallbacks.get(i).onPlay();
        }
        if (shouldNotifyAdPrepareError) {
          shouldNotifyAdPrepareError = false;
          for (int i = 0; i < adCallbacks.size(); i++) {
            adCallbacks.get(i).onError();
          }
        }
        break;
      case IMA_AD_STATE_PAUSED:
        imaAdState = IMA_AD_STATE_PLAYING;
        for (int i = 0; i < adCallbacks.size(); i++) {
          adCallbacks.get(i).onResume();
        }
        break;
      default:
        throw new IllegalStateException();
    }
    if (player == null) {
      // Sometimes messages from IMA arrive after detaching the player. See [Internal: b/63801642].
      Log.w(TAG, "Unexpected playAd while detached");
    } else if (!player.getPlayWhenReady()) {
      adsManager.pause();
    }
  }

  @Override
  public void stopAd() {
    if (DEBUG) {
      Log.d(TAG, "stopAd");
    }
    if (player == null) {
      // Sometimes messages from IMA arrive after detaching the player. See [Internal: b/63801642].
      Log.w(TAG, "Unexpected stopAd while detached");
    }
    if (imaAdState == IMA_AD_STATE_NONE) {
      Log.w(TAG, "Unexpected stopAd");
      return;
    }
    try {
      stopAdInternal();
    } catch (Exception e) {
      maybeNotifyInternalError("stopAd", e);
    }
  }

  @Override
  public void pauseAd() {
    if (DEBUG) {
      Log.d(TAG, "pauseAd");
    }
    if (imaAdState == IMA_AD_STATE_NONE) {
      // This method is called after content is resumed.
      return;
    }
    imaAdState = IMA_AD_STATE_PAUSED;
    for (int i = 0; i < adCallbacks.size(); i++) {
      adCallbacks.get(i).onPause();
    }
  }

  @Override
  public void resumeAd() {
    // This method is never called. See [Internal: b/18931719].
    maybeNotifyInternalError("resumeAd", new IllegalStateException("Unexpected call to resumeAd"));
  }

  // Player.EventListener implementation.

  @Override
  public void onTimelineChanged(Timeline timeline, Object manifest,
      @Player.TimelineChangeReason int reason) {
    if (reason == Player.TIMELINE_CHANGE_REASON_RESET) {
      // The player is being reset and this source will be released.
      return;
    }
    Assertions.checkArgument(timeline.getPeriodCount() == 1);
    this.timeline = timeline;
    long contentDurationUs = timeline.getPeriod(0, period).durationUs;
    contentDurationMs = C.usToMs(contentDurationUs);
    if (contentDurationUs != C.TIME_UNSET) {
      adPlaybackState = adPlaybackState.withContentDurationUs(contentDurationUs);
    }
    updateImaStateForPlayerState();
  }

  @Override
  public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
    if (adsManager == null) {
      return;
    }

    if (imaAdState == IMA_AD_STATE_PLAYING && !playWhenReady) {
      adsManager.pause();
      return;
    }

    if (imaAdState == IMA_AD_STATE_PAUSED && playWhenReady) {
      adsManager.resume();
      return;
    }

    if (imaAdState == IMA_AD_STATE_NONE && playbackState == Player.STATE_BUFFERING
        && playWhenReady) {
      checkForContentComplete();
    } else if (imaAdState != IMA_AD_STATE_NONE && playbackState == Player.STATE_ENDED) {
      // IMA is waiting for the ad playback to finish so invoke the callback now.
      // Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again.
      for (int i = 0; i < adCallbacks.size(); i++) {
        adCallbacks.get(i).onEnded();
      }
      if (DEBUG) {
        Log.d(TAG, "VideoAdPlayerCallback.onEnded in onPlayerStateChanged");
      }
    }
  }

  @Override
  public void onPlayerError(ExoPlaybackException error) {
    if (imaAdState != IMA_AD_STATE_NONE) {
      for (int i = 0; i < adCallbacks.size(); i++) {
        adCallbacks.get(i).onError();
      }
    }
  }

  @Override
  public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
    if (adsManager == null) {
      return;
    }
    if (!playingAd && !player.isPlayingAd()) {
      checkForContentComplete();
      if (sentContentComplete) {
        for (int i = 0; i < adPlaybackState.adGroupCount; i++) {
          if (adPlaybackState.adGroupTimesUs[i] != C.TIME_END_OF_SOURCE) {
            adPlaybackState = adPlaybackState.withSkippedAdGroup(i);
          }
        }
        updateAdPlaybackState();
      } else {
        long positionMs = player.getCurrentPosition();
        timeline.getPeriod(0, period);
        int newAdGroupIndex = period.getAdGroupIndexForPositionUs(C.msToUs(positionMs));
        if (newAdGroupIndex != C.INDEX_UNSET) {
          sentPendingContentPositionMs = false;
          pendingContentPositionMs = positionMs;
          if (newAdGroupIndex != adGroupIndex) {
            shouldNotifyAdPrepareError = false;
          }
        }
      }
    } else {
      updateImaStateForPlayerState();
    }
  }

  // Internal methods.

  private void startAdPlayback() {
    ImaSdkFactory imaSdkFactory = ImaSdkFactory.getInstance();
    AdsRenderingSettings adsRenderingSettings = imaSdkFactory.createAdsRenderingSettings();
    adsRenderingSettings.setEnablePreloading(ENABLE_PRELOADING);
    adsRenderingSettings.setMimeTypes(supportedMimeTypes);
    if (mediaLoadTimeoutMs != TIMEOUT_UNSET) {
      adsRenderingSettings.setLoadVideoTimeout(mediaLoadTimeoutMs);
    }

    // Set up the ad playback state, skipping ads based on the start position as required.
    long[] adGroupTimesUs = getAdGroupTimesUs(adsManager.getAdCuePoints());
    adPlaybackState = new AdPlaybackState(adGroupTimesUs);
    long contentPositionMs = player.getCurrentPosition();
    int adGroupIndexForPosition =
        adPlaybackState.getAdGroupIndexForPositionUs(C.msToUs(contentPositionMs));
    if (adGroupIndexForPosition == 0) {
      podIndexOffset = 0;
    } else if (adGroupIndexForPosition == C.INDEX_UNSET) {
      // There is no preroll and midroll pod indices start at 1.
      podIndexOffset = -1;
    } else /* adGroupIndexForPosition > 0 */ {
      // Skip ad groups before the one at or immediately before the playback position.
      for (int i = 0; i < adGroupIndexForPosition; i++) {
        adPlaybackState = adPlaybackState.withSkippedAdGroup(i);
      }
      // Play ads after the midpoint between the ad to play and the one before it, to avoid issues
      // with rounding one of the two ad times.
      long adGroupForPositionTimeUs = adGroupTimesUs[adGroupIndexForPosition];
      long adGroupBeforeTimeUs = adGroupTimesUs[adGroupIndexForPosition - 1];
      double midpointTimeUs = (adGroupForPositionTimeUs + adGroupBeforeTimeUs) / 2d;
      adsRenderingSettings.setPlayAdsAfterTime(midpointTimeUs / C.MICROS_PER_SECOND);

      // We're removing one or more ads, which means that the earliest ad (if any) will be a
      // midroll/postroll. Midroll pod indices start at 1.
      podIndexOffset = adGroupIndexForPosition - 1;
    }

    if (adGroupIndexForPosition != C.INDEX_UNSET && hasMidrollAdGroups(adGroupTimesUs)) {
      // Provide the player's initial position to trigger loading and playing the ad.
      pendingContentPositionMs = contentPositionMs;
    }

    // Start ad playback.
    adsManager.init(adsRenderingSettings);
    updateAdPlaybackState();
    if (DEBUG) {
      Log.d(TAG, "Initialized with ads rendering settings: " + adsRenderingSettings);
    }
  }

  private void handleAdEvent(AdEvent adEvent) {
    Ad ad = adEvent.getAd();
    switch (adEvent.getType()) {
      case LOADED:
        // The ad position is not always accurate when using preloading. See [Internal: b/62613240].
        AdPodInfo adPodInfo = ad.getAdPodInfo();
        int podIndex = adPodInfo.getPodIndex();
        adGroupIndex =
            podIndex == -1 ? (adPlaybackState.adGroupCount - 1) : (podIndex + podIndexOffset);
        int adPosition = adPodInfo.getAdPosition();
        int adCount = adPodInfo.getTotalAds();
        adsManager.start();
        if (DEBUG) {
          Log.d(TAG, "Loaded ad " + adPosition + " of " + adCount + " in group " + adGroupIndex);
        }
        int oldAdCount = adPlaybackState.adGroups[adGroupIndex].count;
        if (adCount != oldAdCount) {
          if (oldAdCount == C.LENGTH_UNSET) {
            adPlaybackState = adPlaybackState.withAdCount(adGroupIndex, adCount);
            updateAdPlaybackState();
          } else {
            // IMA sometimes unexpectedly decreases the ad count in an ad group.
            Log.w(TAG, "Unexpected ad count in LOADED, " + adCount + ", expected " + oldAdCount);
          }
        }
        if (adGroupIndex != expectedAdGroupIndex) {
          Log.w(
              TAG,
              "Expected ad group index "
                  + expectedAdGroupIndex
                  + ", actual ad group index "
                  + adGroupIndex);
          expectedAdGroupIndex = adGroupIndex;
        }
        break;
      case CONTENT_PAUSE_REQUESTED:
        // After CONTENT_PAUSE_REQUESTED, IMA will playAd/pauseAd/stopAd to show one or more ads
        // before sending CONTENT_RESUME_REQUESTED.
        imaPausedContent = true;
        pauseContentInternal();
        break;
      case STARTED:
        if (ad.isSkippable()) {
          focusSkipButton();
        }
        break;
      case TAPPED:
        if (eventListener != null) {
          eventListener.onAdTapped();
        }
        break;
      case CLICKED:
        if (eventListener != null) {
          eventListener.onAdClicked();
        }
        break;
      case CONTENT_RESUME_REQUESTED:
        imaPausedContent = false;
        resumeContentInternal();
        break;
      case LOG:
        Map<String, String> adData = adEvent.getAdData();
        String message = "AdEvent: " + adData;
        Log.i(TAG, message);
        if ("adLoadError".equals(adData.get("type"))) {
          handleAdGroupLoadError(new IOException(message));
        }
        break;
      case ALL_ADS_COMPLETED:
      default:
        break;
    }
  }

  private void updateImaStateForPlayerState() {
    boolean wasPlayingAd = playingAd;
    int oldPlayingAdIndexInAdGroup = playingAdIndexInAdGroup;
    playingAd = player.isPlayingAd();
    playingAdIndexInAdGroup = playingAd ? player.getCurrentAdIndexInAdGroup() : C.INDEX_UNSET;
    if (!sentContentComplete) {
      boolean adFinished = wasPlayingAd && playingAdIndexInAdGroup != oldPlayingAdIndexInAdGroup;
      if (adFinished) {
        // IMA is waiting for the ad playback to finish so invoke the callback now.
        // Either CONTENT_RESUME_REQUESTED will be passed next, or playAd will be called again.
        for (int i = 0; i < adCallbacks.size(); i++) {
          adCallbacks.get(i).onEnded();
        }
        if (DEBUG) {
          Log.d(TAG, "VideoAdPlayerCallback.onEnded in onTimelineChanged/onPositionDiscontinuity");
        }
      }
      if (!wasPlayingAd && playingAd && imaAdState == IMA_AD_STATE_NONE) {
        int adGroupIndex = player.getCurrentAdGroupIndex();
        // IMA hasn't called playAd yet, so fake the content position.
        fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime();
        fakeContentProgressOffsetMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]);
        if (fakeContentProgressOffsetMs == C.TIME_END_OF_SOURCE) {
          fakeContentProgressOffsetMs = contentDurationMs;
        }
      }
    }
  }

  private void resumeContentInternal() {
    if (imaAdState != IMA_AD_STATE_NONE) {
      imaAdState = IMA_AD_STATE_NONE;
      if (DEBUG) {
        Log.d(TAG, "Unexpected CONTENT_RESUME_REQUESTED without stopAd");
      }
    }
    if (adGroupIndex != C.INDEX_UNSET) {
      adPlaybackState = adPlaybackState.withSkippedAdGroup(adGroupIndex);
      adGroupIndex = C.INDEX_UNSET;
      updateAdPlaybackState();
    }
  }

  private void pauseContentInternal() {
    imaAdState = IMA_AD_STATE_NONE;
    if (sentPendingContentPositionMs) {
      pendingContentPositionMs = C.TIME_UNSET;
      sentPendingContentPositionMs = false;
    }
  }

  private void stopAdInternal() {
    imaAdState = IMA_AD_STATE_NONE;
    int adIndexInAdGroup = adPlaybackState.adGroups[adGroupIndex].getFirstAdIndexToPlay();
    // TODO: Handle the skipped event so the ad can be marked as skipped rather than played.
    adPlaybackState =
        adPlaybackState.withPlayedAd(adGroupIndex, adIndexInAdGroup).withAdResumePositionUs(0);
    updateAdPlaybackState();
    if (!playingAd) {
      adGroupIndex = C.INDEX_UNSET;
    }
  }

  private void handleAdGroupLoadError(Exception error) {
    int adGroupIndex =
        this.adGroupIndex == C.INDEX_UNSET ? expectedAdGroupIndex : this.adGroupIndex;
    if (adGroupIndex == C.INDEX_UNSET) {
      // Drop the error, as we don't know which ad group it relates to.
      return;
    }
    AdPlaybackState.AdGroup adGroup = adPlaybackState.adGroups[adGroupIndex];
    if (adGroup.count == C.LENGTH_UNSET) {
      adPlaybackState =
          adPlaybackState.withAdCount(adGroupIndex, Math.max(1, adGroup.states.length));
      adGroup = adPlaybackState.adGroups[adGroupIndex];
    }
    for (int i = 0; i < adGroup.count; i++) {
      if (adGroup.states[i] == AdPlaybackState.AD_STATE_UNAVAILABLE) {
        if (DEBUG) {
          Log.d(TAG, "Removing ad " + i + " in ad group " + adGroupIndex);
        }
        adPlaybackState = adPlaybackState.withAdLoadError(adGroupIndex, i);
      }
    }
    updateAdPlaybackState();
    if (pendingAdLoadError == null) {
      pendingAdLoadError = AdLoadException.createForAdGroup(error, adGroupIndex);
    }
  }

  private void handleAdPrepareError(int adGroupIndex, int adIndexInAdGroup, Exception exception) {
    if (DEBUG) {
      Log.d(
          TAG, "Prepare error for ad " + adIndexInAdGroup + " in group " + adGroupIndex, exception);
    }
    if (imaAdState == IMA_AD_STATE_NONE) {
      // Send IMA a content position at the ad group so that it will try to play it, at which point
      // we can notify that it failed to load.
      fakeContentProgressElapsedRealtimeMs = SystemClock.elapsedRealtime();
      fakeContentProgressOffsetMs = C.usToMs(adPlaybackState.adGroupTimesUs[adGroupIndex]);
      if (fakeContentProgressOffsetMs == C.TIME_END_OF_SOURCE) {
        fakeContentProgressOffsetMs = contentDurationMs;
      }
      shouldNotifyAdPrepareError = true;
    } else {
      // We're already playing an ad.
      if (adIndexInAdGroup > playingAdIndexInAdGroup) {
        // Mark the playing ad as ended so we can notify the error on the next ad and remove it,
        // which means that the ad after will load (if any).
        for (int i = 0; i < adCallbacks.size(); i++) {
          adCallbacks.get(i).onEnded();
        }
      }
      playingAdIndexInAdGroup = adPlaybackState.adGroups[adGroupIndex].getFirstAdIndexToPlay();
      for (int i = 0; i < adCallbacks.size(); i++) {
        adCallbacks.get(i).onError();
      }
    }
    adPlaybackState = adPlaybackState.withAdLoadError(adGroupIndex, adIndexInAdGroup);
    updateAdPlaybackState();
  }

  private void checkForContentComplete() {
    if (contentDurationMs != C.TIME_UNSET && pendingContentPositionMs == C.TIME_UNSET
        && player.getContentPosition() + END_OF_CONTENT_POSITION_THRESHOLD_MS >= contentDurationMs
        && !sentContentComplete) {
      adsLoader.contentComplete();
      if (DEBUG) {
        Log.d(TAG, "adsLoader.contentComplete");
      }
      sentContentComplete = true;
    }
  }

  private void updateAdPlaybackState() {
    // Ignore updates while detached. When a player is attached it will receive the latest state.
    if (eventListener != null) {
      eventListener.onAdPlaybackState(adPlaybackState);
    }
  }

  private void focusSkipButton() {
    if (playingAd && adUiViewGroup != null && adUiViewGroup.getChildCount() > 0
        && adUiViewGroup.getChildAt(0) instanceof WebView) {
      WebView webView = (WebView) (adUiViewGroup.getChildAt(0));
      webView.requestFocus();
      webView.loadUrl(FOCUS_SKIP_BUTTON_WORKAROUND_JS);
    }
  }

  /**
   * Returns the next ad index in the specified ad group to load, or {@link C#INDEX_UNSET} if all
   * ads in the ad group have loaded.
   */
  private int getAdIndexInAdGroupToLoad(int adGroupIndex) {
    @AdState int[] states = adPlaybackState.adGroups[adGroupIndex].states;
    int adIndexInAdGroup = 0;
    // IMA loads ads in order.
    while (adIndexInAdGroup < states.length
        && states[adIndexInAdGroup] != AdPlaybackState.AD_STATE_UNAVAILABLE) {
      adIndexInAdGroup++;
    }
    return adIndexInAdGroup == states.length ? C.INDEX_UNSET : adIndexInAdGroup;
  }

  private void maybeNotifyPendingAdLoadError() {
    if (pendingAdLoadError != null && eventListener != null) {
      eventListener.onAdLoadError(pendingAdLoadError, new DataSpec(adTagUri));
      pendingAdLoadError = null;
    }
  }

  private void maybeNotifyInternalError(String name, Exception cause) {
    String message = "Internal error in " + name;
    Log.e(TAG, message, cause);
    // We can't recover from an unexpected error in general, so skip all remaining ads.
    if (adPlaybackState == null) {
      adPlaybackState = new AdPlaybackState();
    } else {
      for (int i = 0; i < adPlaybackState.adGroupCount; i++) {
        adPlaybackState = adPlaybackState.withSkippedAdGroup(i);
      }
    }
    updateAdPlaybackState();
    if (eventListener != null) {
      eventListener.onAdLoadError(
          AdLoadException.createForUnexpected(new RuntimeException(message, cause)),
          new DataSpec(adTagUri));
    }
  }

  private static long[] getAdGroupTimesUs(List<Float> cuePoints) {
    if (cuePoints.isEmpty()) {
      // If no cue points are specified, there is a preroll ad.
      return new long[] {0};
    }

    int count = cuePoints.size();
    long[] adGroupTimesUs = new long[count];
    int adGroupIndex = 0;
    for (int i = 0; i < count; i++) {
      double cuePoint = cuePoints.get(i);
      if (cuePoint == -1.0) {
        adGroupTimesUs[count - 1] = C.TIME_END_OF_SOURCE;
      } else {
        adGroupTimesUs[adGroupIndex++] = (long) (C.MICROS_PER_SECOND * cuePoint);
      }
    }
    // Cue points may be out of order, so sort them.
    Arrays.sort(adGroupTimesUs, 0, adGroupIndex);
    return adGroupTimesUs;
  }

  private static boolean isAdGroupLoadError(AdError adError) {
    // TODO: Find out what other errors need to be handled (if any), and whether each one relates to
    // a single ad, ad group or the whole timeline.
    return adError.getErrorCode() == AdErrorCode.VAST_LINEAR_ASSET_MISMATCH;
  }

  private static boolean hasMidrollAdGroups(long[] adGroupTimesUs) {
    int count = adGroupTimesUs.length;
    if (count == 1) {
      return adGroupTimesUs[0] != 0 && adGroupTimesUs[0] != C.TIME_END_OF_SOURCE;
    } else if (count == 2) {
      return adGroupTimesUs[0] != 0 || adGroupTimesUs[1] != C.TIME_END_OF_SOURCE;
    } else {
      // There's at least one midroll ad group, as adGroupTimesUs is never empty.
      return true;
    }
  }
}


text:
module Faceauth
  module ApplicationHelper
  end
end


text:
namespace password_manager {

class PasswordStoreInterface;

// The production code implementation of FormSaver.
class FormSaverImpl : public FormSaver {
 public:
  // |store| needs to outlive |this| and will be used for all
  // PasswordStoreInterface operations.
  explicit FormSaverImpl(PasswordStoreInterface* store);

  FormSaverImpl(const FormSaverImpl&) = delete;
  FormSaverImpl& operator=(const FormSaverImpl&) = delete;

  ~FormSaverImpl() override;

  // FormSaver:
  PasswordForm Blocklist(PasswordFormDigest digest) override;
  void Unblocklist(const PasswordFormDigest& digest) override;
  void Save(PasswordForm pending,
            const std::vector<const PasswordForm*>& matches,
            const std::u16string& old_password) override;
  void Update(PasswordForm pending,
              const std::vector<const PasswordForm*>& matches,
              const std::u16string& old_password) override;
  void UpdateReplace(PasswordForm pending,
                     const std::vector<const PasswordForm*>& matches,
                     const std::u16string& old_password,
                     const PasswordForm& old_unique_key) override;
  void Remove(const PasswordForm& form) override;
  std::unique_ptr<FormSaver> Clone() override;

 private:
  // The class is stateless. Don't introduce it. The methods are utilities for
  // common tasks on the password store. The state should belong to either a
  // form handler or origin handler which could embed FormSaver.

  // Cached pointer to the PasswordStoreInterface.
  const raw_ptr<PasswordStoreInterface> store_;
};

}  // namespace password_manager

#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_SAVER_IMPL_H_