text:
(function() {
    if (document.hmcontext === undefined) {
        document.hmcontext = {};
    }
    document.hmcontext.newEngine = function newEngine() {
        var xprivate = {};     // strictly for use of the test runner
        var xpublic = {};
        var units = "px";
        var borderWidth = 2;

        // see exposeMembersForUnitTests re the this.length problem
        gatherMixins(0 /*this.length*/, arguments, xprivate);

        /// main entry point
        /// usage eg.: document.hmcontext.newEngine.drawHeatMap( [{area:49}...], {left:20...});
        xpublic.drawHeatMap = function(heatMapData) {
            var lo = newLayout();
            tiles = lo.layoutTiles(heatMapData );
            var renderParams = null;
            {
                renderParams = {left:20,top:20,width:500,height:500};
                units = "px";
                borderWidth = 2;
            }
            var rr = newRenderer(renderParams);
            rr.renderLayout(tiles);
        };
        /**
         Layout
         ------
         This is identified as "Naive".

         the main entry point is layoutTiles which takes an array of areas (numbers) and lays them out (i.e.
         sets top, left, height and width) within a square equal to the aggregate of all the areas.  The
         laid out areas are called 'Tiles' and the total area in which they are placed is defined as a 'Rectangle'.

         The routine takes each area at a time and places the 'tile' along either the full width or the full height of the
         rectangle (or whatever part of the rectangle is still unpopulated).  The decision as to whether to
         align with the width or the height depends on which is shorter.  Aligning on a shorter side improves the
         look of squareness so is always selected.

         In fact if we view each attempt to populate the unpopulated rectangle as a 'turn' then it should
         be noted that an attempt is made to align multiple tiles (all along the same side of the
         unpopulated rectangle) during each turn.  Larger and larger sets of tiles are tested as long as the
         squareness factor continues to increase.

         I'm not sure where the algorithm came from (we are talking 2010.  I may have come up with it myself
         but it seems a bit clever for me.  The code is almost certainly mine.  I don't think the algo's
         Bruis, Huizing and Van Wijk because there is no attempt to compare width-wise layout with
         length-wise layout and it does not pick up on their succinct functional style.
         */
        var newLayout = xpublic.newLayout = function newLayout() {
            var xpublic = {};
            var xprivate = {};

            var calcTotalArea = function(heatMapData, numTiles) {
                if ( typeof numTiles !== 'number' ) {
                    numTiles = heatMapData.length;
                }
                var tot = 0;
                for ( var ii = 0; ii < numTiles; ii++ ) {
                    tot += heatMapData[ii].area;
                }
                return tot;
            };

            var sc = newSquarenessCalculator();
            /// adds tiles to the committedTiles array from heatMap data
            /// @param nuMTiles - the number of tiles to add
            /// @param remainingRect provides coordinates for the tiles
            /// @param side - the side along which the tiles are aligned.
            /// @param length - the length of the side along which the tiles are alinged.
            /// #param committedTiles - array into which tiles are added.
            var commitTiles = xprivate.commitTiles = function commitTiles(heatMapData
                , numTiles, remainingRect, side, length, committedTiles)
            {
                var totalArea = calcTotalArea(heatMapData, numTiles);
                var curTop = remainingRect.get_top();
                var curLeft = remainingRect.get_left();
                for (var ii = 0; ii < numTiles; ii++)
                {
                    var width;
                    var height;
                    if (side === 'width')
                    {
                        width = length * (heatMapData[ii].area / totalArea );
                        height = heatMapData[ii].area / width;
                    }
                    else
                    {
                        height = length * (heatMapData[ii].area / totalArea );
                        width = heatMapData[ii].area / height;
                    }
                    var tile = newTile(curLeft, curTop, width, height, heatMapData[ii]);
                    committedTiles.push(tile);
                    if (side === 'width')
                    {
                        curLeft += tile.get_width();
                    }
                    else
                    {
                        curTop += tile.get_height();
                    }
                }
                return totalArea;
            };
            /// @return an array of tiles for displaying
            xpublic.layoutTiles = function layoutTiles(heatMapData ) {
                assert( typeof heatMapData === 'object' && typeof heatMapData.push === 'function'
                    , "Layout.layouTiles: heatMapData must be an array of areas");
                var committedTiles = [];
                var area = calcTotalArea(heatMapData );
                var sideLength = Math.sqrt(area);
                var rect = newRectangle(0,0, sideLength, sideLength );

                layoutRectangle(heatMapData, rect, committedTiles );
                return committedTiles;
            };
            /// remainingRect shrinks and committedTiles list grows as the routine is called recursively
            ///
            /// the tile to be placed will take up the complete shorter side of the available
            /// unused rectangle (remainingRect) as this must necessarily provide the squarer geometry
            function layoutRectangle(heatMapData, remainingRect, committedTiles ) {
                assert( typeof heatMapData === 'object' && typeof heatMapData.push === 'function'
                    , "Layout.layouTiles: heatMapData must be an array of areas");
                assert( typeof committedTiles === 'object' && typeof committedTiles.push === 'function'
                    , "Layout.layouTiles: committedTiles must be an array of areas");
                assert( typeof remainingRect === 'object' && typeof remainingRect.get_remainingRect === 'function'
                    , "Layout.layoutTiles: remainingRect must be a Rectangle");

                var side = remainingRect.shortestSide();
                var length = side === 'width' ? remainingRect.get_width() : remainingRect.get_height();
                var seqAreas = newSequence(heatMapData);
                var numTiles = sc.tileCountForSide(seqAreas, length);
                assert( numTiles <= seqAreas.length()
                    , "the squareness calculator has allocated more tiles than are available" );
                var totalArea = commitTiles(heatMapData, numTiles, remainingRect, side, length, committedTiles);
                if ( heatMapData.length > numTiles ) {
                    remainingRect = remainingRect.get_remainingRect(side, totalArea );
                    layoutRectangle(heatMapData.slice(numTiles), remainingRect, committedTiles );
                }
            };
            exposeMembersForUnitTests(this.length, arguments, xpublic, xprivate);
            return xpublic;     // Layout
        };

        /// tile contains the data to draw an appropriate rectangle on the heatmap
        var newTile = xprivate.newTile = function newTile(left, top, width, height, extraData) {
            assert( typeof(left) === 'number'
                && typeof(top) === 'number'
                && typeof(width) === 'number'
                && typeof(height) === 'number'
            );
            var xpublic = {};
            xpublic.get_left = function get_left() {
                return left;
            };
            xpublic.get_top = function get_top() {
                return top;
            };
            xpublic.get_width = function get_width() {
                return width;
            };
            xpublic.get_height = function get_height() {
                return height;
            };
            xpublic.get_area = function get_area() {
                return width * height;
            };
            xpublic.get_extraData = function get_extraData() {
                return extraData === undefined ? {} : extraData;
            };
            xpublic.renderInnerTile = function renderInnerTile() {};
//        /// if you add arbitrary properties to the tile when you creeate it
//        /// then you can query them with this
//        xpublic.get_property = function(propertyName) {
//            return spec[propertyName];
//        };
            return xpublic;
        };

        // newRectangle extends Tile (adding get_remainingRect() and shortestSide()
        var newRectangle = xprivate.newRectangle = function newRectangle(left, top, width, height) {
            assert( width > 0 && height > 0, "cannot handle a rectangle with zero area or an anti-rectangle");
            var xpublic = newTile(left, top, width, height);
            var get_area = xpublic.get_area;
            var get_left = xpublic.get_left;
            var get_top = xpublic.get_top;
            var get_width = xpublic.get_width;
            var get_height = xpublic.get_height;
            /// @param givenSide the side that is already fixed must be 'height' or 'width'
            ///
            xpublic.get_remainingRect = function (givenSide, areaToRemove ) {
                var newLeft;
                var newTop;
                var newWidth;
                var newHeight;
                if ( givenSide === 'height') {
                    var removedWidth = areaToRemove / get_height();
                    newLeft = get_left() + removedWidth;
                    newTop = get_top();
                    newWidth = get_width() - removedWidth;
                    newHeight = get_height();
                }
                else {
                    assert( givenSide === 'width', "get_reaminingRect: side must be either 'width' or 'height'");
                    var removedHeight = areaToRemove / get_width();
                    newLeft = get_left();
                    newTop = get_top() + removedHeight;
                    newWidth = get_width();
                    newHeight = get_height() - removedHeight;
                }
                return newRectangle(newLeft, newTop, newWidth, newHeight );
            };
            xpublic.shortestSide = function shortestSide() {
                return width < height ? 'width' : 'height';
            };
            return xpublic;
        };

        /// utility class that converts an array to a lisp style sequence with head and tail etc.
        /// the sequence is backed by an unchanging array
        var newSequence = xprivate.newSequence = function newSequence(arr, pos)
        {
            if ( typeof pos === 'undefined') {
                pos = 0;
            }
            var xpublic = {};
            var head = xpublic.head = function head() {
                if ( arr.length > pos ) {
                    return arr[pos];
                }
                else
                {
                    return null;
                }
            };
            var isEmpty = xpublic.isEmpty = function isEmpty() {
                return head() === null;
            };

            var tail = xpublic.tail = function tail() {
                assert( pos  < arr.length, "Squence.tail: attempt to tail an  empty sequence");
                return newSequence( arr, pos + 1);
            };
            var length = xpublic.length = function length() {
                return arr.length - pos;
            }
            return xpublic;
        };

        /// for some set of areas (numbers) and some length the calculator will determine what number of adjacent
        /// areas will provide the set of squarest looking rectangles given that the rectangles are aligned
        /// and that the length of the aligned sides is equal to the given length.
        ///
        /// note that the squarenessCalculator only affects the number of tiles that can be aligned
        /// in this turn.  It does not determine which side of the unpopulated rectangle should
        /// be used for aligning the tile(s).
        var newSquarenessCalculator = xprivate.newSquarenessCalculator !== undefined
            ? xprivate.newSquarenessCalculator : xprivate.newSquarenessCalculator = function getSquarenessCalculator() {
            var xpublic = {};
            var xprivate = {};

            /// for a set of areas plus an optional extra area this calculates
            /// the aggregate squareness factor given that all areas have to have one side whose
            /// totals add up to length
            /// @return the ratio of two adjacent sides of the rectangle such that the ration is >= 1 (squareness factor)
            /// @param areas - the areas that we have already decided to commit
            /// @param extraArea - an area that we might decide to add to the above if its addition improves squareness
            /// @param length - typically the shortest side of some rectangle in which we intend to place the areas
            var squareness = xprivate.squareness = function squareness(areas, extraArea, length) {
                assert( typeof areas !== 'undefined' && areas !== null
                    , "newSquarenessCalculator.squareness: requires an non-empty array of areas" );
                assert( typeof areas.push !== 'undefined'
                    , "newSquarenessCalculator.squareness: requires an array of area");
                assert( extraArea !== 'undefined' && extraArea != null
                    , "newSquarenessCalculator.squareness: requires an extra area of type {area:nn}.  It can can have an area of 0" );
                assert( typeof length === 'number', "newSquarenessCalculator.squareness: requires a length");
                var numAreas = areas.length + extraArea.area > 0 ? 1 : 0 ;
                var totalArea = function totalArea() {
                        var tot = 0;
                        for ( var ii = 0; ii < areas.length; ii++ ) {
                            tot += areas[ii].area;
                        }
                        return tot;
                    }() + extraArea.area;
                var sq = 0;
                for ( var ii = 0; ii < areas.length; ii++ ) {
                    var height = length * areas[ii].area / totalArea;
                    var width = areas[ii].area / height;
                    sq += (Math.max( height / width, width / height ));
                }
                if ( extraArea.area > 0 ) {
                    height = length * extraArea.area / totalArea;
                    width = extraArea.area / height;
                    sq += (Math.max( height / width, width / height ));
                }
                assert( sq >= numAreas);
                return sq / numAreas;
            };
            /// returns the optimal number of sequential tiles in the sequence
            /// which provide the squarest tiles for the given length.
            /// i.e. in a 'turn' we add the number of tiles which creates the greatest squareness factor
            /// @param seqAreas sequence of type {area:nnn}
            /// @param length - this is typically either the width or the height of
            ///   a rectangle along which the tiles are placed.
            var squarestTileCount = xprivate.squarestTileCount
                = function squarestTileCount(seqAreas, length) {
                assert( !seqAreas.isEmpty()
                    , "squarenesCalculateor.squarestTileCount: cannot handle an empty sequence of tiles");
                assert( typeof seqAreas.head().area === 'number'
                    , "the tile sequence must contain raw objects containing an area property");
                /// areasPart shrinks and areasToCommit grows as this function is executed recursively
                function doSquarestTileCount(areasPart, length, areasToCommit) {
                    if (areasPart.isEmpty())  {
                        return areasToCommit.length;    // all areas in heapMapdata have been committed except these
                                                        // last few (in areasTocommit)
                    }
                    if ( squareness(areasToCommit, areasPart.head(), length) <= squareness(areasToCommit, {area:0}, length)) {
                        areasToCommit.push(areasPart.head());
                        return doSquarestTileCount(areasPart.tail(), length, areasToCommit );
                    }
                    else    // squareness won't improve by adding another area
                    {
                        return areasToCommit.length;
                    }
                };
                return doSquarestTileCount( seqAreas.tail(), length, [seqAreas.head()] );
            };
            xpublic.tileCountForSide = function tileCountForSide(seqAreas, length ) {
                return squarestTileCount(seqAreas, length );
            };
            exposeMembersForUnitTests(this.length, arguments, xpublic, xprivate);
            return xpublic;
        };
        /// this has sole charge of rendering the constructed layout in the browser
        /// renderLayout takes a set of "tiles" which have positions and dimensions expressed
        /// in "real-world" units.  These positions and dimensions are scaled by the Renderer
        /// to fit the canvas passed to newRenderer.
        var newRenderer = xpublic.newRenderer = function newRenderer(canvasRect) {
            assert( typeof(canvasRect.left) === 'number' && typeof(canvasRect.top) === 'number'
                && typeof(canvasRect.width) === 'number' && typeof(canvasRect.height) === 'number'
                ,"canvasRect passed to renderer constructor must contain left, top, width, height");
            assert( canvasRect.width > 0 && canvasRect.height > 0 );

            var spublic = {};

            function renderTile(tile, left, top, width, height, idx, tiles) {
                var div = writeTileHTML(left, top, width, height, 0 );
                tile.renderInnerTile(div, idx, tiles);
            };
            function writeTileHTML( left, top, width, height, backgroundColor ) {
                debugPrint( "left="+left+" top="+top+" width="+width+" height=" +height);

                var divTag = document.createElement("div");
                divTag.style.position = "absolute";
                divTag.style.left = left+units;
                divTag.style.top = top+units;
                divTag.style.width = width+units;
                divTag.style.height = height+units;
                divTag.style.border = borderWidth + units + " solid rgb(153,0,153)";
                //divTag.style.backgroundColor = "green";
                var divDataPanel = document.getElementById("DataPanel");
                divDataPanel.appendChild(divTag);
                return divTag;
            };
            function calcTotalArea(tiles) {
                var tot = 0;
                for ( var ii = 0; ii < tiles.length; ii++ ) {
                    tot += tiles[ii].get_area();
                }
                return tot;
            }
            spublic.renderLayout = function renderLayout( tiles, renderInnerTile) {
                try {
                    if (renderInnerTile === undefined) {
                        renderInnerTile = function(div) {
                            div.style.backgroundColor = "green";
                            div.innnerHTML = "long way home";
                        };
                    }
                    document.getElementById("DataPanel").innerHTML = "<div/>";
                    var totalArea = calcTotalArea(tiles);
                    var xScale = canvasRect.width / Math.sqrt(totalArea);
                    var yScale = canvasRect.height / Math.sqrt(totalArea);
                    for ( var ii = 0; ii < tiles.length; ii++ ) {
                        tiles[ii].renderInnerTile = renderInnerTile;
                        renderTile(tiles[ii]
                            , canvasRect.left + tiles[ii].get_left() * xScale
                            , canvasRect.top + tiles[ii].get_top() * yScale
                            , tiles[ii].get_width() * xScale
                            , tiles[ii].get_height() * yScale
                            , ii, tiles
                        );
                    }
                }
                catch ( ex ) {
                    alert( "renderLayout:" + ex );
                }
            };
            return spublic;
        };
        /// usage:
        /// var heatmpaMembers = {};
        /// document.hmcontext.newEngine(heatMapmembers);
        /// var tile = heatmapMembers.newTile();  etc., etc.
        ///
        /// newLaout(layoutMembers);
        /// layoutMembers.commitTiles etc.
        function exposeMembersForUnitTests(numNamedArgs, args, xpublic, xprivate) {
            var copyMembers = function copyMembers(members, source) {
                for ( var member in source ) {
                    if (source.hasOwnProperty(member)) {
                        members[member] = source[member];
                    }
                }
            };
            if (args.length > numNamedArgs && args[numNamedArgs] != null) { // an extra arg has been passed to obtain the set of private functions
                var argsArray;
                argsArray = Array.prototype.slice.call(args);
                var members = argsArray[numNamedArgs];
                copyMembers(members, xpublic);
                copyMembers(members, xprivate);
            }
        }

        function gatherMixins(numNamedArgs, args, xprivate) {
            var copyMembers = function copyMembers(members, source) {
                for ( var member in source ) {
                    if (source.hasOwnProperty(member)) {
                        members[member] = source[member];
                    }
                }
            };
            var POS_HIDDEN_PARAM = 1;
            if (args.length > numNamedArgs + POS_HIDDEN_PARAM && args[numNamedArgs + POS_HIDDEN_PARAM] != null) {
                // two extra args have been passed
                // 1) to obtain the set of private functions
                // 2) mixins
                var argsArray;
                argsArray = Array.prototype.slice.call(args);
                var members = argsArray[numNamedArgs + POS_HIDDEN_PARAM];
                copyMembers(xprivate, members);
            }

        }

        var debugPrint = function(str) {
//        document.writeln( str + "<br>" );
        };
        var assert = function(cond, message ) {
            if (!cond ) {
                throw { name: "assertionFailure", message: message };
            }
        };
        exposeMembersForUnitTests(0 /*this.length*/, arguments, xpublic, xprivate);
                // TODO would ideally use aregs.length here.  - the 'this' problem gets in the way.
                // The call to the newEngine function is qualified by document.hmcontext which makes this.length undefined.
                // presumably when 'this' referred to a free function it worked whereas document.hmcontext
                // has no such member as 'length'
        return xpublic;
    };
})();


text:
"""Generically-useful IBodyProducer implementations"""

import json

from twisted.internet import defer
from twisted.web import iweb
from zope.interface import implements

# Disable missing '__init__' method | pylint: disable=W0232
class IMIMEBodyProducer(iweb.IBodyProducer):
  """Interface that extends an 'IBodyProducer' allow it to supply a MIME type.
  """

  def getMIMEType(self):
    """
    Returns the MIME type for this body producer
    Returns: (str) The MIME type
    """

# Disable missing '__init__' method | pylint: disable=W0232
class IReusableBodyProducer(iweb.IBodyProducer):
  """Interface that extends an 'IBodyProducer' allow it to reset its state."""

  def reset(self):
    """Resets body producer's state, so it can be reused."""

class StringBodyProducer(object):
  """An IBodyProducer implementation that directly produces a string."""
  implements(IMIMEBodyProducer, IReusableBodyProducer)

  def __init__(self, body_str, mime_type=None):
    self._body_str = body_str
    self.body_str = body_str

    self.mime_type = mime_type
    if self.mime_type is None:
      self.mime_type = 'text/plain'

  @property
  def length(self):
    return len(self.body_str)

  def reset(self):
    self.body_str = self._body_str

  # IMIMEBodyProducer
  def getMIMEType(self):
    return self.mime_type

  def startProducing(self, consumer):
    consumer.write(self.body_str)
    self.body_str = ''
    return defer.succeed(None)

  def stopProducing(self):
    pass

  def pauseProducing(self):
    pass

  def resumeProducing(self):
    pass

class JsonBodyProducer(StringBodyProducer):
  """An IBodyProducer implementation that produces the JSON associated with a
  Python dictionary."""

  def __init__(self, json_dict):
    StringBodyProducer.__init__(
        self,
        json.dumps(json_dict),
        mime_type='application/json')

redpajama_set_name: RedPajamaGithub


text:
<?php
// PHP Upload Script for CKEditor:  http://coursesweb.net/

// HERE SET THE PATH TO THE FOLDER WITH IMAGES ON YOUR SERVER (RELATIVE TO THE ROOT OF YOUR WEBSITE ON SERVER)
$upload_dir = '/upload_dir/';

// HERE PERMISSIONS FOR IMAGE
$imgsets = array(
 'maxsize' => 2000,          // maximum file size, in KiloBytes (2 MB)
 'maxwidth' => 900,          // maximum allowed width, in pixels
 'maxheight' => 800,         // maximum allowed height, in pixels
 'minwidth' => 10,           // minimum allowed width, in pixels
 'minheight' => 10,          // minimum allowed height, in pixels
 'type' => array('bmp', 'gif', 'jpg', 'jpe', 'png')        // allowed extensions
);

$re = '';

if(isset($_FILES['upload']) && strlen($_FILES['upload']['name']) > 1) {
  $upload_dir = trim($upload_dir, '/') .'/';
  $img_name = basename($_FILES['upload']['name']);

  // get protocol and host name to send the absolute image path to CKEditor
  $protocol = !empty($_SERVER['HTTPS']) ? 'https://' : 'http://';
  $site = $protocol. $_SERVER['SERVER_NAME'] .'/';

  $uploadpath = $_SERVER['DOCUMENT_ROOT'] .'/'. $upload_dir . $img_name;       // full file path
  $sepext = explode('.', strtolower($_FILES['upload']['name']));
  $type = end($sepext);       // gets extension
  list($width, $height) = getimagesize($_FILES['upload']['tmp_name']);     // gets image width and height
  $err = '';         // to store the errors

  // Checks if the file has allowed type, size, width and height (for images)
  if(!in_array($type, $imgsets['type'])) $err .= 'The file: '. $_FILES['upload']['name']. ' has not the allowed extension type.';
  if($_FILES['upload']['size'] > $imgsets['maxsize']*1000) $err .= '\\n Maximum file size must be: '. $imgsets['maxsize']. ' KB.';
  if(isset($width) && isset($height)) {
    if($width > $imgsets['maxwidth'] || $height > $imgsets['maxheight']) $err .= '\\n Width x Height = '. $width .' x '. $height .' \\n The maximum Width x Height must be: '. $imgsets['maxwidth']. ' x '. $imgsets['maxheight'];
    if($width < $imgsets['minwidth'] || $height < $imgsets['minheight']) $err .= '\\n Width x Height = '. $width .' x '. $height .'\\n The minimum Width x Height must be: '. $imgsets['minwidth']. ' x '. $imgsets['minheight'];
  }

  // If no errors, upload the image, else, output the errors
  if($err == '') {
    if(move_uploaded_file($_FILES['upload']['tmp_name'], $uploadpath)) {
      $CKEditorFuncNum = $_GET['CKEditorFuncNum'];
      $url = $site. $upload_dir . $img_name;
      $message = $img_name .' successfully uploaded: \\n- Size: '. number_format($_FILES['upload']['size']/1024, 3, '.', '') .' KB \\n- Image Width x Height: '. $width. ' x '. $height;
      $re = "window.parent.CKEDITOR.tools.callFunction($CKEditorFuncNum, '$url', '$message')";
    }
    else $re = 'alert("Unable to upload the file")';
  }
  else $re = 'alert("'. $err .'")';
}
echo "<script>$re;</script>";


text:
using System;

namespace SevenZip.Compression.LZ
{
	internal interface IMatchFinder : IInWindowStream
	{
		void Create(uint historySize, uint keepAddBufferBefore, uint matchMaxLen, uint keepAddBufferAfter);

		uint GetMatches(uint[] distances);

		void Skip(uint num);
	}
}


text:
package org.apache.sis.storage.netcdf;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.LinkedHashSet;
import java.util.LinkedHashMap;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.io.IOException;
import javax.measure.Unit;
import javax.measure.UnitConverter;
import javax.measure.IncommensurableException;
import javax.measure.format.ParserException;

import org.opengis.util.CodeList;
import org.opengis.util.InternationalString;
import org.opengis.metadata.Metadata;
import org.opengis.metadata.Identifier;
import org.opengis.metadata.spatial.*;
import org.opengis.metadata.content.*;
import org.opengis.metadata.citation.*;
import org.opengis.metadata.identification.*;
import org.opengis.metadata.maintenance.ScopeCode;
import org.opengis.metadata.constraint.Restriction;
import org.opengis.referencing.cs.AxisDirection;
import org.opengis.referencing.crs.VerticalCRS;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import org.apache.sis.util.iso.Types;
import org.apache.sis.util.iso.DefaultNameFactory;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.event.StoreListeners;
import org.apache.sis.metadata.iso.DefaultMetadata;
import org.apache.sis.metadata.iso.citation.*;
import org.apache.sis.metadata.iso.identification.*;
import org.apache.sis.metadata.sql.MetadataStoreException;
import org.apache.sis.internal.netcdf.Axis;
import org.apache.sis.internal.netcdf.Decoder;
import org.apache.sis.internal.netcdf.Variable;
import org.apache.sis.internal.netcdf.VariableRole;
import org.apache.sis.internal.netcdf.Dimension;
import org.apache.sis.internal.netcdf.Grid;
import org.apache.sis.internal.storage.io.IOUtilities;
import org.apache.sis.internal.storage.MetadataBuilder;
import org.apache.sis.internal.storage.wkt.StoreFormat;
import org.apache.sis.internal.referencing.AxisDirections;
import org.apache.sis.internal.util.CollectionsExt;
import org.apache.sis.internal.util.Strings;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.CharSequences;
import org.apache.sis.referencing.CRS;
import org.apache.sis.measure.Units;
import org.apache.sis.math.Vector;

// The following dependency is used only for static final String constants.
// Consequently, the compiled class files should not have this dependency.
import ucar.nc2.constants.ACDD;
import ucar.nc2.constants.CDM;
import ucar.nc2.constants.CF;

import static java.util.Collections.singleton;
import static org.apache.sis.storage.netcdf.AttributeNames.*;

/**
 * Mapping from netCDF metadata to ISO 19115-2 metadata. The {@link String} constants declared in
 * the {@linkplain AttributeNames parent class} are the name of attributes examined by this class.
 * The current implementation searches the attribute values in the following places, in that order:
 *
 *

 *
{@code "NCISOMetadata"} group

 *
{@code "CFMetadata"} group

 *
Global attributes

 *
{@code "THREDDSMetadata"} group

 *

 *
 * The {@code "CFMetadata"} group has precedence over the global attributes because the
 * {@linkplain AttributeNames#LONGITUDE longitude} and {@linkplain AttributeNames#LATITUDE latitude}
 * resolutions are often more accurate in that group.
 *
 *
Known limitations

 *

 *
{@code "degrees_west"} and {@code "degrees_south"} units not correctly handled.

 *
Units of measurement not yet declared in the {@link Band} elements.

 *
{@link AttributeNames#FLAG_VALUES} and {@link AttributeNames#FLAG_MASKS}
 *       not yet included in the {@link RangeElementDescription} elements.

 *
Services (WMS, WCS, OPeNDAP, THREDDS) etc.) and transfer options not yet declared.

 *

 *
 * @author  Martin Desruisseaux (Geomatys)
 * @author  Thi Phuong Hao Nguyen (VNSC)
 * @author  Alexis Manin (Geomatys)
 * @version 1.3
 * @since   0.3
 * @module
 */
final class MetadataReader extends MetadataBuilder {
    /**
     * Whether the reader should include experimental fields.
     * They are fields for which we are unsure of the proper ISO 19115 location.
     */
    private static final boolean EXPERIMENTAL = true;

    /**
     * Names of global attributes identifying services.
     */
    private static final String[] SERVICES = {"wms_service", "wcs_service"};

    /**
     * The character to use as a separator in comma-separated list. This separator is used for parsing the
     * {@link AttributeNames#KEYWORDS} attribute value for instance.
     */
    private static final char SEPARATOR = ',';

    /**
     * The character to use for quoting strings in a comma-separated list. Quoted strings may contain comma.
     *
     *
Example:
     * John Doe, Jane Lee, "L J Smith, Jr."
     *

     */
    private static final char QUOTE = '"';

    /**
     * The source of netCDF attributes from which to infer ISO metadata.
     * This source is set at construction time.
     *
     *
This {@code MetadataReader} class does not close this source.
     * Closing this source after usage is the user responsibility.

     */
    private final Decoder decoder;

    /**
     * The actual search path, as a subset of {@link org.apache.sis.internal.netcdf.Convention#SEARCH_PATH}
     * with only the name of the groups which have been found in the NeCDF file.
     */
    private final String[] searchPath;

    /**
     * The contact, used at metadata creation time for avoiding to construct identical objects
     * more than once.
     *
     *
The point of contact is stored in the two following places. The semantic of those two
     * contacts is not strictly identical, but the distinction is not used in netCDF file:

     *
     *

     *
{@link DefaultMetadata#getContacts()}

     *
{@link DefaultDataIdentification#getPointOfContacts()}

     *

     *
     * An object very similar is used as the creator. The point of contact and the creator
     * are often identical except for their role attribute.
     */
    private transient ResponsibleParty pointOfContact;

    /**
     * The vertical coordinate reference system to be given to the object created by {@link #addExtent()}.
     * This is set to the first vertical CRS found.
     */
    private VerticalCRS verticalCRS;

    /**
     * Whether at least one grid coverage has been found during iteration over variables.
     */
    private boolean hasGridCoverages;

    /**
     * Creates a new netCDF to ISO mapper for the given source.
     *
     * @param  decoder  the source of netCDF attributes.
     */
    MetadataReader(final Decoder decoder) {
        this.decoder = decoder;
        decoder.setSearchPath(decoder.convention().getSearchPath());
        searchPath = decoder.getSearchPath();
    }

    /**
     * Invoked when a non-fatal exception occurred while reading metadata.
     * This method sends a record to the registered listeners if any,
     * or logs the record otherwise.
     */
    private void warning(final Exception e) {
        decoder.listeners.warning(e);
    }

    /**
     * Logs a warning using the localized error resource bundle for the locale given by
     * {@link StoreListeners#getLocale()}.
     *
     * @param  key  one of {@link Errors.Keys} values.
     */
    private void warning(final short key, final Object p1, final Object p2, final Exception e) {
        final StoreListeners listeners = decoder.listeners;
        listeners.warning(Errors.getResources(listeners.getLocale()).getString(key, p1, p2), e);
    }

    /**
     * Splits comma-separated values. Leading and trailing spaces are removed for each item
     * unless the item is between double quotes. Empty strings are ignored unless between double quotes.
     * If a value begin with double quotes, all content will be copied verbatim until the closing double quote.
     * A double quote is considered as a closing double quote if just before a comma separator (ignoring spaces).
     */
    static List<String> split(final String value) {
        if (value == null) {
            return Collections.emptyList();
        }
        final List<String> items = new ArrayList<>();
        int start = 0;      // Index of the first character of the next item to add in the list.
        int end;            // Index after the last character of the next item to add in the list.
        int next;           // Index of the next separator (comma) after `end`.
        final int length = CharSequences.skipTrailingWhitespaces(value, 0, value.length());
split:  while ((start = CharSequences.skipLeadingWhitespaces(value, start, length)) < length) {
            if (value.charAt(start) == QUOTE) {
                next = ++start;                                 // Skip the quote character.
                do {
                    end = value.indexOf(QUOTE, next);           // End of quoted text, may have comma separator before.
                    if (end < 0) break split;
                    next = CharSequences.skipLeadingWhitespaces(value, end+1, length);
                } while (next < length && value.charAt(next) != SEPARATOR);
            } else {
                next = value.indexOf(SEPARATOR, start);         // Unquoted text - comma is the item separator.
                if (next < 0) break;
                end = CharSequences.skipTrailingWhitespaces(value, start, next);
            }
            if (start != end) {
                items.add(value.substring(start, end));
            }
            start = next+1;
        }
        if (start < length) {
            items.add(value.substring(start, length));
        }
        return items;
    }

    /**
     * Reads the attribute value for the given name, then trims the leading and trailing spaces.
     * If the value is null, empty or contains only spaces, then this method returns {@code null}.
     */
    private String stringValue(final String name) {
        return Strings.trimOrNull(decoder.stringValue(name));
    }

    /**
     * Reads the numeric value for the given value, or returns {@code NaN} if none.
     */
    private double numericValue(final String name) {
        final Number v = decoder.numericValue(name);
        return (v != null) ? v.doubleValue() : Double.NaN;
    }

    /**
     * Returns the enumeration constant for the given name, or {@code null} if the given name is not recognized.
     * In the latter case, this method emits a warning.
     */
    private <T extends Enum<T>> T forEnumName(final Class<T> enumType, final String name) {
        final T code = Types.forEnumName(enumType, name);
        if (code == null && name != null) {
            warning(Errors.Keys.UnknownEnumValue_2, enumType, name, null);
        }
        return code;
    }

    /**
     * Returns the code value for the given name, or {@code null} if the given name is not recognized.
     * In the latter case, this method emits a warning.
     */
    private <T extends CodeList<T>> T forCodeName(final Class<T> codeType, final String name) {
        final T code = Types.forCodeName(codeType, name, false);
        if (code == null && name != null) {
            /*
             * CodeLists are not enums, but using the error message for enums is not completly wrong since
             * if we did not allowed CodeList to create new elements, then we are using it like an enum.
             */
            warning(Errors.Keys.UnknownEnumValue_2, codeType, name, null);
        }
        return code;
    }

    /**
     * Adds the given element in the given collection if the element is non-null.
     * If the element is non-null and the collection is null, a new collection is
     * created. The given collection, or the new collection if it has been created,
     * is returned.
     */
    private static <T> Set<T> addIfNonNull(Set<T> collection, final T element) {
        if (element != null) {
            if (collection == null) {
                collection = new LinkedHashSet<>(4);
            }
            collection.add(element);
        }
        return collection;
    }

    /**
     * Returns {@code true} if the given netCDF attribute is either null or equals to the
     * string value of the given metadata value.
     *
     * @param metadata  The value stored in the metadata object.
     * @param attribute The value parsed from the netCDF file.
     */
    private static boolean canShare(final CharSequence metadata, final String attribute) {
        return (attribute == null) || (metadata != null && metadata.toString().equals(attribute));
    }

    /**
     * Returns {@code true} if the given netCDF attribute is either null or equals to one
     * of the values in the given collection.
     *
     * @param  metadata   the value stored in the metadata object.
     * @param  attribute  the value parsed from the netCDF file.
     */
    private static boolean canShare(final Collection<String> metadata, final String attribute) {
        return (attribute == null) || metadata.contains(attribute);
    }

    /**
     * Returns {@code true} if the given URL is null, or if the given resource contains that URL.
     *
     * @param  resource  the value stored in the metadata object.
     * @param  url       the value parsed from the netCDF file.
     */
    private static boolean canShare(final OnlineResource resource, final String url) {
        return (url == null) || (resource != null && canShare(resource.getLinkage().toString(), url));
    }

    /**
     * Returns {@code true} if the given email is null, or if the given address contains that email.
     *
     * @param  address  the value stored in the metadata object.
     * @param  email    the value parsed from the netCDF file.
     */
    private static boolean canShare(final Address address, final String email) {
        return (email == null) || (address != null && canShare(address.getElectronicMailAddresses(), email));
    }

    /**
     * Creates a URI form the given path, or returns {@code null} if the given URL is null or cannot be parsed.
     * In the latter case, a warning will be emitted.
     */
    private URI createURI(final String url) {
        if (url != null) try {
            return new URI(url);
        } catch (URISyntaxException e) {
            warning(e);
        }
        return null;
    }

    /**
     * Creates an {@code OnlineResource} element if the given URL is not null. Since ISO 19115
     * declares the URL as a mandatory attribute, this method will ignore all other attributes
     * if the given URL is null.
     *
     * @param  url   the URL (mandatory - if {@code null}, no resource will be created).
     * @return the online resource, or {@code null} if the URL was null.
     */
    private OnlineResource createOnlineResource(final String url) {
        final URI uri = createURI(url);
        if (uri == null) {
            return null;
        }
        final DefaultOnlineResource resource = new DefaultOnlineResource(uri);
        final String protocol = uri.getScheme();
        resource.setProtocol(protocol);
        if ("http".equalsIgnoreCase(protocol) || "https".equalsIgnoreCase(protocol)) {
            resource.setApplicationProfile("web browser");
        }
        resource.setFunction(OnLineFunction.INFORMATION);
        return resource;
    }

    /**
     * Creates an {@code Address} element if at least one of the given attributes is non-null.
     */
    private static Address createAddress(final String email) {
        if (email != null) {
            final DefaultAddress address = new DefaultAddress();
            address.setElectronicMailAddresses(singleton(email));
            return address;
        }
        return null;
    }

    /**
     * Creates a {@code Contact} element if at least one of the given attributes is non-null.
     */
    private static Contact createContact(final Address address, final OnlineResource url) {
        if (address != null || url != null) {
            final DefaultContact contact = new DefaultContact();
            if (address != null) contact.setAddresses(singleton(address));
            if (url     != null) contact.setOnlineResources(singleton(url));
            return contact;
        }
        return null;
    }

    /**
     * Creates a {@code Responsibility} element if at least one of the name, email or URL attributes is defined.
     * For more consistent results, the caller should restrict the {@linkplain Decoder#setSearchPath search path}
     * to a single group before invoking this method.
     *
     *
Implementation note: this method tries to reuse the existing {@link #pointOfContact} instance,
     * or part of it, if it is suitable.

     *
     * @param  keys              the group of attribute names to use for fetching the values.
     * @param  isPointOfContact  {@code true} if this responsible party is the "main" one. This will force the
     *         role to {@link Role#POINT_OF_CONTACT} and enable the use of {@code "institution"} attribute as
     *         a fallback if there is no value for {@link Responsible#INSTITUTION}.
     * @return the responsible party, or {@code null} if none.
     *
     * @see AttributeNames#CREATOR
     * @see AttributeNames#CONTRIBUTOR
     * @see AttributeNames#PUBLISHER
     */
    private ResponsibleParty createResponsibleParty(final Responsible keys, final boolean isPointOfContact) {
        String individualName   = stringValue(keys.NAME);
        String organisationName = stringValue(keys.INSTITUTION);
        final String email      = stringValue(keys.EMAIL);
        final String url        = stringValue(keys.URL);
        if (organisationName == null && isPointOfContact) {
            organisationName = stringValue("institution");
        }
        if (individualName == null && organisationName == null && email == null && url == null) {
            return null;
        }
        /*
         * The "individual" name may actually be an institution name, either because a "*_type" attribute
         * said so or because the "individual" name is the same than the institution name. In such cases,
         * reorganize the names in order to avoid duplication.
         */
        if (organisationName == null) {
            if (isOrganisation(keys)) {
                organisationName = individualName;
                individualName = null;
            }
        } else if (organisationName.equalsIgnoreCase(individualName)) {
            individualName = null;
        }
        Role role = forCodeName(Role.class, stringValue(keys.ROLE));
        if (role == null) {
            role = isPointOfContact ? Role.POINT_OF_CONTACT : keys.DEFAULT_ROLE;
        }
        /*
         * Verify if we can share the existing `pointOfContact` instance. This is often the case in practice.
         * If we cannot share the whole existing instance, we usually can share parts of it like the address.
         */
        ResponsibleParty responsibility = pointOfContact;
        Contact          contact        = null;
        Address          address        = null;
        OnlineResource   resource       = null;
        if (responsibility != null) {
            { // Additional indentation for having the same level than SIS branches for GeoAPI snapshots (makes merges easier).
                contact = responsibility.getContactInfo();
                if (contact != null) {
                    address  = contact.getAddress();
                    resource = contact.getOnlineResource();
                }
                if (!canShare(resource, url)) {
                    resource       = null;
                    contact        = null;                  // Clear the parents all the way up to the root.
                    responsibility = null;
                }
                if (!canShare(address, email)) {
                    address        = null;
                    contact        = null;                  // Clear the parents all the way up to the root.
                    responsibility = null;
                }
                if (responsibility != null) {
                    if (!canShare(responsibility.getOrganisationName(), organisationName) ||
                        !canShare(responsibility.getIndividualName(),   individualName))
                    {
                        responsibility = null;
                    }
                }
            }
        }
        /*
         * If we cannot share the exiting instance, we have to build a new one. If there is both
         * an individual and organisation name, then the individual is considered a member of the
         * organisation. This structure shall be kept consistent with the check in the above block.
         */
        if (responsibility == null) {
            if (contact == null) {
                if (address  == null) address  = createAddress(email);
                if (resource == null) resource = createOnlineResource(url);
                contact = createContact(address, resource);
            }
            if (individualName != null || organisationName != null || contact != null) {        // Do not test role.
                AbstractParty party = null;
                if (individualName   != null) party = new DefaultIndividual(individualName, null, null);
                if (organisationName != null) party = new DefaultOrganisation(organisationName, null, (DefaultIndividual) party, null);
                if (party            == null) party = isOrganisation(keys) ? new DefaultOrganisation() : new DefaultIndividual();
                if (contact          != null) party.setContactInfo(singleton(contact));
                responsibility = new DefaultResponsibleParty(role);
                ((DefaultResponsibleParty) responsibility).setParties(singleton(party));
            }
        }
        return responsibility;
    }

    /**
     * Returns {@code true} if the responsible party described by the given keys is an organization.
     * In case of doubt, this method returns {@code false}. This is consistent with ACDD recommendation,
     * which set the default value to {@code "person"}.
     */
    private boolean isOrganisation(final Responsible keys) {
        final String type = stringValue(keys.TYPE);
        return "institution".equalsIgnoreCase(type) || "group".equalsIgnoreCase(type);
    }

    /**
     * Adds a {@code DataIdentification/Citation} element if at least one of the required attributes is non-null.
     * This method will initialize the {@link #pointOfContact} field, then reuses it if non-null and suitable.
     *
     *
This method opportunistically collects the name of all publishers.
     * Those names are useful to {@link #addIdentificationInfo(Set)}.

     *
     * @return the name of all publishers, or {@code null} if none.
     */
    private Set<InternationalString> addCitation() {
        String title = stringValue(TITLE);
        if (title == null) {
            title = stringValue("full_name");   // THREDDS attribute documented in TITLE javadoc.
            if (title == null) {
                title = stringValue("name");    // THREDDS attribute documented in TITLE javadoc.
                if (title == null) {
                    title = decoder.getTitle();
                }
            }
        }
        addTitle(title);
        addEdition(stringValue(PRODUCT_VERSION));
        addOtherCitationDetails(stringValue(REFERENCES));
        addCitationDate(decoder.dateValue(METADATA_CREATION), DateType.CREATION,    Scope.ALL);
        addCitationDate(decoder.dateValue(METADATA_MODIFIED), DateType.REVISION,    Scope.ALL);
        addCitationDate(decoder.dateValue(DATE_CREATED),      DateType.CREATION,    Scope.RESOURCE);
        addCitationDate(decoder.dateValue(DATE_MODIFIED),     DateType.REVISION,    Scope.RESOURCE);
        addCitationDate(decoder.dateValue(DATE_ISSUED),       DateType.PUBLICATION, Scope.RESOURCE);
        /*
         * Add the responsible party which is declared in global attributes, or in
         * the THREDDS attributes if no information was found in global attributes.
         * This responsible party is taken as the point of contact.
         */
        for (final String path : searchPath) {
            decoder.setSearchPath(path);
            final ResponsibleParty party = createResponsibleParty(CREATOR, true);
            if (party != pointOfContact) {
                addPointOfContact(party, Scope.RESOURCE);
                if (pointOfContact == null) {
                    pointOfContact = party;
                }
            }
        }
        /*
         * There is no distinction in netCDF files between "point of contact" and "creator".
         * We take the first one as the data originator.
         */
        addCitedResponsibleParty(pointOfContact, Role.ORIGINATOR);
        /*
         * Add the contributors only after we did one full pass over the creators. We keep those two
         * loops separated in order to increase the chances that pointOfContact has been initialized
         * (it may not have been initialized on the first pass).
         */
        Set<InternationalString> publisher = null;
        for (final String path : searchPath) {
            decoder.setSearchPath(path);
            final ResponsibleParty contributor = createResponsibleParty(CONTRIBUTOR, false);
            if (contributor != pointOfContact) {
                addCitedResponsibleParty(contributor, null);
            }
            final ResponsibleParty r = createResponsibleParty(PUBLISHER, false);
            if (r instanceof DefaultResponsibility) {
                addDistributor(r);
                for (final AbstractParty party : ((DefaultResponsibility) r).getParties()) {
                    publisher = addIfNonNull(publisher, party.getName());
                }
            }
        }
        decoder.setSearchPath(searchPath);
        return publisher;
    }

    /**
     * Adds a {@code DataIdentification} element if at least one of the required attributes is non-null.
     *
     * @param  publisher   the publisher names, built by the caller in an opportunist way.
     */
    private void addIdentificationInfo(final Set<InternationalString> publisher) throws IOException, DataStoreException {
        boolean     hasExtent = false;
        Set<String> project   = null;
        Set<String> standard  = null;
        final Set<String> keywords = new LinkedHashSet<>();
        for (final String path : searchPath) {
            decoder.setSearchPath(path);
            keywords.addAll(split(stringValue(KEYWORDS.TEXT)));
            standard = addIfNonNull(standard, stringValue(STANDARD_NAME.TEXT));
            project  = addIfNonNull(project,  stringValue(PROJECT));
            for (final String keyword : split(stringValue(ACCESS_CONSTRAINT))) {
                addAccessConstraint(forCodeName(Restriction.class, keyword));
            }
            addTopicCategory(forCodeName(TopicCategory.class, stringValue(TOPIC_CATEGORY)));
            addSpatialRepresentation(forCodeName(SpatialRepresentationType.class, stringValue(DATA_TYPE)));
            if (!hasExtent) {
                /*
                 * Takes only ONE extent, because a netCDF file may declare many time the same
                 * extent with different precision. The groups are ordered in such a way that
                 * the first extent should be the most accurate one.
                 */
                hasExtent = addExtent();
            }
        }
        /*
         * For the following properties, use only the first non-empty attribute value found on the search path.
         */
        decoder.setSearchPath(searchPath);
        addAbstract               (stringValue(SUMMARY));
        addPurpose                (stringValue(PURPOSE));
        addSupplementalInformation(stringValue(COMMENT));
        addCredits                (stringValue(ACKNOWLEDGEMENT));
        addCredits                (stringValue("acknowledgment"));          // Legacy spelling.
        addUseLimitation          (stringValue(LICENSE));
        addKeywords(standard,  KeywordType.THEME,       stringValue(STANDARD_NAME.VOCABULARY));
        addKeywords(keywords,  KeywordType.THEME,       stringValue(KEYWORDS.VOCABULARY));
        addKeywords(project,   KeywordType.valueOf("PROJECT"), null);
        addKeywords(publisher, KeywordType.valueOf("DATA_CENTRE"), null);
        /*
         * Add geospatial bounds as a geometric object. This optional operation requires
         * an external library (ESRI or JTS) to be present on the classpath.
         */
        final String wkt = stringValue(GEOSPATIAL_BOUNDS);
        if (wkt != null) {
            addBoundingPolygon(new StoreFormat(null, null, decoder.geomlib, decoder.listeners).parseGeometry(wkt,
                    stringValue(GEOSPATIAL_BOUNDS + "_crs"), stringValue(GEOSPATIAL_BOUNDS + "_vertical_crs")));
        }
        final String[] format = decoder.getFormatDescription();
        String id = format[0];
        if (NetcdfStoreProvider.NAME.equalsIgnoreCase(id)) try {
            setPredefinedFormat(NetcdfStoreProvider.NAME);
            id = null;
        } catch (MetadataStoreException e) {
            // Will add `id` at the end of this method.
            warning(e);
        }
        if (format.length >= 2) {
            addFormatName(format[1]);
            if (format.length >= 3) {
                setFormatEdition(format[2]);
            }
        }
        addFormatName(id);          // Do nothing is `id` is null.
    }

    /**
     * Adds information about axes and cell geometry.
     * This is the {@code <mdb:spatialRepresentationInfo>} element in XML.
     * We work on grid axes instead of Coordinate Reference System axes because
     * {@code metadata/spatialRepresentationInfo/axisDimensionProperties/dimensionSize} seems to imply that.
     *
     * @param  cs  the grid geometry (related to the netCDF coordinate system).
     * @throws ArithmeticException if the size of an axis exceeds {@link Integer#MAX_VALUE}, or other overflow occurs.
     */
    private void addSpatialRepresentationInfo(final Axis[] axes) throws IOException, DataStoreException {
        for (int i=0; i<axes.length; i++) {
            final Axis axis = axes[i];
            /*
             * Axes usually have exactly one dimension. However, some netCDF axes are backed by a two-dimensional
             * conversion grid. In such case, our Axis constructor should have ensured that the first element in
             * the `sourceDimensions` and `sourceSizes` arrays are for the grid dimension which is most closely
             * oriented toward the axis direction.
             */
            final int d = i;    // Because lambda expressions want final variable.
            axis.getMainSize().ifPresent((s) -> setAxisSize(d, s));
            final AttributeNames.Dimension attributeNames;
            switch (axis.abbreviation) {
                case 'λ': case 'θ':           attributeNames = AttributeNames.LONGITUDE; break;
                case 'φ': case 'Ω':           attributeNames = AttributeNames.LATITUDE;  break;
                case 'h': case 'H': case 'D': attributeNames = AttributeNames.VERTICAL;  break;
                case 't': case 'T':           attributeNames = AttributeNames.TIME;      break;
                default : continue;
            }
            final DimensionNameType name = attributeNames.DEFAULT_NAME_TYPE;
            setAxisName(i, name);
            final String res = stringValue(attributeNames.RESOLUTION);
            if (res != null) try {
                /*
                 * ACDD convention recommends to write units after the resolution.
                 * Examples: "100 meters", "0.1 degree".
                 */
                final int s = res.indexOf(' ');
                final double value;
                Unit<?> units = null;
                if (s < 0) {
                    value = numericValue(attributeNames.RESOLUTION);
                } else {
                    value = Double.parseDouble(res.substring(0, s).trim());
                    final String symbol = res.substring(s+1).trim();
                    if (!symbol.isEmpty()) try {
                        units = Units.valueOf(symbol);
                    } catch (ParserException e) {
                        warning(Errors.Keys.CanNotAssignUnitToDimension_2, name, units, e);
                    }
                }
                setAxisResolution(i, value, units);
            } catch (NumberFormatException e) {
                warning(e);
            }
        }
        setCellGeometry(CellGeometry.AREA);
    }

    /**
     * Adds the extent declared in the current group. For more consistent results, the caller should restrict
     * the {@linkplain Decoder#setSearchPath search path} to a single group before invoking this method.
     * The {@link #verticalCRS} field should have been set before to invoke this method.
     *
     * @return {@code true} if at least one numerical value has been added.
     */
    private boolean addExtent() {
        addExtent(stringValue(GEOGRAPHIC_IDENTIFIER));
        final double[] extent = new double[4];
        /*
         * If at least one geographic coordinate is available, add a GeographicBoundingBox.
         */
        boolean hasExtent;
        hasExtent  = fillExtent(LONGITUDE, Units.DEGREE, AxisDirection.EAST,  extent, 0);
        hasExtent |= fillExtent(LATITUDE,  Units.DEGREE, AxisDirection.NORTH, extent, 2);
        if (hasExtent) {
            addExtent(extent, 0);
            hasExtent = true;
        }
        /*
         * If at least one vertical coordinate is available, add a VerticalExtent.
         */
        if (fillExtent(VERTICAL, Units.METRE, null, extent, 0)) {
            addVerticalExtent(extent[0], extent[1], verticalCRS);
            hasExtent = true;
        }
        /*
         * Get the start and end times as Date objects if available, or as numeric values otherwise.
         * In the latter case, the unit symbol tells how to convert to Date objects.
         */
        Date startTime = decoder.dateValue(TIME.MINIMUM);
        Date endTime   = decoder.dateValue(TIME.MAXIMUM);
        if (startTime == null && endTime == null) {
            final Number tmin = decoder.numericValue(TIME.MINIMUM);
            final Number tmax = decoder.numericValue(TIME.MAXIMUM);
            if (tmin != null || tmax != null) {
                final String symbol = stringValue(TIME.UNITS);
                if (symbol != null) {
                    final Date[] dates = decoder.numberToDate(symbol, tmin, tmax);
                    startTime = dates[0];
                    endTime   = dates[1];
                }
            }
        }
        /*
         * If at least one time value above is available, add a temporal extent.
         */
        if (startTime != null || endTime != null) {
            addTemporalExtent(startTime, endTime);
            hasExtent = true;
        }
        return hasExtent;
    }

    /**
     * Fills one dimension of the geographic bounding box or vertical extent.
     * The extent values are written in the given {@code extent} array.
     *
     * @param  dim         the dimension for which to get the extent.
     * @param  targetUnit  the destination unit of the extent.
     * @param  positive    the direction considered positive, or {@code null} if the unit symbol is not expected to contain a direction.
     * @param  extent      where to store the minimum and maximum values.
     * @param  index       index where to store the minimum value in {@code extent}. The maximum value is stored at {@code index+1}.
     * @return {@code true} if a minimum or a maximum value has been found.
     */
    private boolean fillExtent(final AttributeNames.Dimension dim, final Unit<?> targetUnit, final AxisDirection positive,
                               final double[] extent, final int index)
    {
        double min = numericValue(dim.MINIMUM);
        double max = numericValue(dim.MAXIMUM);
        boolean hasExtent = !Double.isNaN(min) || !Double.isNaN(max);
        if (hasExtent) {
            final String symbol = stringValue(dim.UNITS);
            if (symbol != null) {
                try {
                    final UnitConverter c = Units.valueOf(symbol).getConverterToAny(targetUnit);
                    min = c.convert(min);
                    max = c.convert(max);
                } catch (ParserException | IncommensurableException e) {
                    warning(e);
                }
                boolean reverse = false;
                if (positive != null) {
                    reverse = AxisDirections.opposite(positive).equals(Axis.direction(symbol));
                } else if (dim.POSITIVE != null) {
                    // For now, only the vertical axis have a "positive" attribute.
                    reverse = CF.POSITIVE_DOWN.equals(stringValue(dim.POSITIVE));
                }
                if (reverse) {
                    final double tmp = min;
                    min = -max;
                    max = -tmp;
                }
            }
        }
        extent[index  ] = min;
        extent[index+1] = max;
        return hasExtent;
    }

    /**
     * Adds information about acquisition (program, platform).
     */
    private void addAcquisitionInfo() {
        final Term[] attributes = {
            AttributeNames.PROGRAM,
            AttributeNames.PLATFORM,
            AttributeNames.INSTRUMENT
        };
        for (int i=0; i<attributes.length; i++) {
            final Term at = attributes[i];
            final String authority = stringValue(at.VOCABULARY);
            for (final String keyword : split(stringValue(at.TEXT))) {
                switch (i) {
                    case 0: {
                        if (EXPERIMENTAL) {
                            addAcquisitionOperation(authority, keyword);
                        }
                        break;
                    }
                    case 1: addPlatform  (authority, keyword); break;
                    case 2: addInstrument(authority, keyword); break;
                }
            }
        }
    }

    /**
     * Adds information about all netCDF variables. This is the {@code <mdb:contentInfo>} element in XML.
     * This method groups variables by their domains, i.e. variables having the same set of axes are grouped together.
     */
    @SuppressWarnings("null")
    private void addContentInfo() {
        /*
         * Prepare a list of features and coverages, but without writing metadata now.
         * We differ metadata writing for giving us a chance to group related contents.
         */
        final Set<Dimension> features = new LinkedHashSet<>();
        final Map<List<String>, List<Variable>> coverages = new LinkedHashMap<>(4);
        for (final Variable variable : decoder.getVariables()) {
            if (VariableRole.isCoverage(variable)) {
                final List<org.apache.sis.internal.netcdf.Dimension> dimensions = variable.getGridDimensions();
                final String[] names = new String[dimensions.size()];
                for (int i=0; i<names.length; i++) {
                    names[i] = dimensions.get(i).getName();
                }
                CollectionsExt.addToMultiValuesMap(coverages, Arrays.asList(names), variable);
                hasGridCoverages = true;
            } else if (variable.getRole() == VariableRole.FEATURE_PROPERTY) {
                /*
                 * For feature property, we should take only the first dimension.
                 * If a second dimension exists, it is for character strings.
                 */
                features.add(variable.getGridDimensions().get(0));
            }
        }
        /*
         * Now write the metadata. Note that the spatial repersentation types added below are actually
         * parts of `DataIdentification` instead of `ContentInformation`, but we add them here because
         * we have the information here.
         */
        if (!features .isEmpty()) addSpatialRepresentation(SpatialRepresentationType.TEXT_TABLE);
        if (!coverages.isEmpty()) addSpatialRepresentation(SpatialRepresentationType.GRID);
        for (final Dimension feature : features) {
            final String name = feature.getName();
            if (name != null) {
                addFeatureType(decoder.nameFactory.createLocalName(decoder.namespace, name), feature.length());
            }
        }
        final String processingLevel = stringValue(PROCESSING_LEVEL);
        for (final List<Variable> group : coverages.values()) {
            /*
             * Instantiate a CoverageDescription for each distinct set of netCDF dimensions
             * (e.g. longitude,latitude,time). This separation is based on the fact that a
             * coverage has only one domain for every range of values.
             */
            newCoverage(false);
            setProcessingLevelCode(null, processingLevel);
            for (final Variable variable : group) {
                addSampleDimension(variable);
                final CharSequence[] names    = variable.getAttributeAsStrings(FLAG_NAMES, ' ');
                final CharSequence[] meanings = variable.getAttributeAsStrings(FLAG_MEANINGS, ' ');
                final Vector         masks    = variable.getAttributeAsVector (FLAG_MASKS);
                final Vector         values   = variable.getAttributeAsVector (FLAG_VALUES);
                final int s1 = (names    != null) ? names.length    : 0;
                final int s2 = (meanings != null) ? meanings.length : 0;
                final int s3 = (masks    != null) ? masks .size()   : 0;
                final int s4 = (values   != null) ? values.size()   : 0;
                final int length = Math.max(s1, Math.max(s2, Math.max(s3, s4)));
                for (int i=0; i<length; i++) {
                    addSampleValueDescription(variable,
                            (i < s1) ? names     [i] : null,
                            (i < s2) ? meanings  [i] : null,
                            (i < s3) ? masks .get(i) : null,
                            (i < s4) ? values.get(i) : null);
                }
            }
        }
    }

    /**
     * Adds metadata about a sample dimension (or band) from the given variable.
     * This is the {@code <mrc:dimension>} element in XML.
     *
     * @param  variable  the netCDF variable.
     */
    private void addSampleDimension(final Variable variable) {
        newSampleDimension();
        final String name = Strings.trimOrNull(variable.getName());
        if (name != null) {
            final DefaultNameFactory f = decoder.nameFactory;
            final StringBuilder buffer = new StringBuilder(20);
            variable.writeDataTypeName(buffer);
            setBandIdentifier(f.createMemberName(null, name, f.createTypeName(null, buffer.toString())));
        }
        final String id = Strings.trimOrNull(variable.getStandardName());
        if (!id.equals(name)) {
            addBandName(variable.getAttributeAsString(ACDD.standard_name_vocabulary), id);
        }
        final String description = Strings.trimOrNull(variable.getDescription());
        if (description != null && !description.equals(name) && !description.equals(id)) {
            addBandDescription(description);
        }
        setSampleUnits(variable.getUnit());
        setTransferFunction(variable.getAttributeAsDouble(CDM.SCALE_FACTOR),
                            variable.getAttributeAsDouble(CDM.ADD_OFFSET));
        addContentType(forCodeName(CoverageContentType.class, stringValue(ACDD.coverage_content_type)));
    }

    /**
     * Adds metadata about the meaning of a sample value.
     * This is the {@code <mrc:rangeElementDescription>} element in XML.
     *
     *
Note: ISO 19115 range elements are approximately equivalent to
     * {@code org.apache.sis.coverage.Category} in the {@code sis-coverage} module.

     *
     * @param  variable  the netCDF variable.
     * @param  name      one of the elements in the {@link AttributeNames#FLAG_NAMES} attribute, or {@code null}.
     * @param  meaning   one of the elements in the {@link AttributeNames#FLAG_MEANINGS} attribute or {@code null}.
     * @param  mask      one of the elements in the {@link AttributeNames#FLAG_MASKS} attribute or {@code null}.
     * @param  value     one of the elements in the {@link AttributeNames#FLAG_VALUES} attribute or {@code null}.
     */
    private void addSampleValueDescription(final Variable variable,
            final CharSequence name, final CharSequence meaning, final Number mask, final Number value)
    {
        addSampleValueDescription(name, meaning);
        // TODO: create a record from values (and possibly from the masks).
        //       if (pixel & mask == value) then we have that range element.
    }

    /**
     * Adds a globally unique identifier for the current netCDF {@linkplain #decoder}.
     * The current implementation builds the identifier from the following attributes:
     *
     *

     *
{@code AttributeNames.IDENTIFIER.VOCABULARY} used as the {@linkplain Identifier#getAuthority() authority}.

     *
{@code AttributeNames.IDENTIFIER.TEXT}, or {@link ucar.nc2.NetcdfFile#getId()} if no identifier attribute was found,
     *       or the filename without extension if {@code getId()} returned nothing.

     *

     *
     * This method should be invoked last, after we made our best effort to set the title.
     */
    private void addFileIdentifier() {
        String identifier = stringValue(IDENTIFIER.TEXT);
        String authority;
        if (identifier != null) {
            authority = stringValue(IDENTIFIER.VOCABULARY);
        } else {
            identifier = decoder.getId();
            if (identifier == null) {
                identifier = IOUtilities.filenameWithoutExtension(decoder.getFilename());
                if (identifier == null) {
                    return;
                }
            }
            authority = null;
        }
        if (authority == null) {
            addTitleOrIdentifier(identifier, Scope.RESOURCE);
        } else {
            addIdentifier(authority, identifier, Scope.RESOURCE);
        }
    }

    /**
     * Creates an ISO {@code Metadata} object from the information found in the netCDF file.
     * The returned metadata is unmodifiable, for allowing the caller to share a unique instance.
     *
     * @return the ISO metadata object.
     * @throws IOException if an I/O operation was necessary but failed.
     * @throws DataStoreException if a logical error occurred.
     * @throws ArithmeticException if the size of an axis exceeds {@link Integer#MAX_VALUE}, or other overflow occurs.
     */
    public Metadata read() throws IOException, DataStoreException {
        for (final CoordinateReferenceSystem crs : decoder.getReferenceSystemInfo()) {
            addReferenceSystem(crs);
            if (verticalCRS == null) {
                verticalCRS = CRS.getVerticalComponent(crs, false);
            }
        }
        addResourceScope(ScopeCode.DATASET, null);
        addIdentificationInfo(addCitation());
        for (final String service : SERVICES) {
            final String name = stringValue(service);
            if (name != null) {
                addResourceScope(ScopeCode.SERVICE, name);
            }
        }
        addAcquisitionInfo();
        addContentInfo();
        /*
         * Add the dimension information, if any. This metadata node
         * is built from the netCDF CoordinateSystem objects.
         */
        for (final Grid cs : decoder.getGridCandidates()) {
            if (cs.getSourceDimensions() >= Grid.MIN_DIMENSION) {
                final Axis[] axes = cs.getAxes(decoder);
                if (axes.length >= Grid.MIN_DIMENSION) {
                    addSpatialRepresentationInfo(axes);
                }
            }
        }
        setISOStandards(hasGridCoverages);
        addFileIdentifier();
        /*
         * Departure: UnidataDD2MI.xsl puts the source in Metadata.dataQualityInfo.lineage.statement.
         * However, since ISO 19115:2014, Metadata.resourceLineage.statement seems a more appropriate place.
         * See https://issues.apache.org/jira/browse/SIS-361
         */
        for (final String path : searchPath) {
            decoder.setSearchPath(path);
            addLineage(stringValue(HISTORY));
            addSource(stringValue(SOURCE), null, null);
        }
        decoder.setSearchPath(searchPath);
        final DefaultMetadata metadata = build();
        addCompleteMetadata(createURI(stringValue(METADATA_LINK)));
        metadata.transitionTo(DefaultMetadata.State.FINAL);
        return metadata;
    }
}


text:
import SettingsModal from 'flarum/components/SettingsModal';

export default class InstructionsSettingsModal extends SettingsModal {
  className() {
    return 'InstructionsSettingsModal';
  }

  title() {
    return 'Instructions Settings';
  }

  form() {
    return [

        Start a Discussion Instructions
        <textarea className="FormControl" bidi={this.setting('instructions.start_instructions')}/>

        Hide for users with more than
        <input className="FormControl" type="number" min="0" bidi={this.setting('instructions.start_instructions_max_discussions')}/>
        discussions

,

        Reply Instructions
        <textarea className="FormControl" bidi={this.setting('instructions.reply_instructions')}/>

        Hide for users with more than
        <input className="FormControl" type="number" min="0" bidi={this.setting('instructions.reply_instructions_max_posts')}/>
        posts

    ];
  }
}


text:
using namespace std;

class NormalClass
{
     public:  const int &getI() const;
              const char &getC() const;
     private: int i;
              char b;
              char c;
};

class EmptyClass
{

};

class DerivedEmptyClass: public EmptyClass
{

};

class AbstractClass
{
  public:
          virtual void funcOne() = 0;
          virtual void funcTwo() = 0; // Virtual pointer
};

class DerivedAbstractClass: public AbstractClass
{
public:
          virtual void funcOne() = 0;
          virtual void funcTwo() = 0; // Virtual pointer
};

class NotAbstrClass
{
  public: int Func( int );
          long Func( char );
          //virtual int funcMe();
};

class MixClass
{
  public:
          virtual void clFunc( int ); // Virtual pointer
          static int i; // Not part of object of class so no contribution
          int j;
          char k;
};

int main()
{
    // Print size of class or class objects
    cout<<"Size of Normal class: "<< sizeof(NormalClass)<<endl;
    cout<<"Size of empty class: "<< sizeof(EmptyClass)<<endl;
    cout<<"Size of Abstract class :"<< sizeof(AbstractClass)<<endl;
    cout<<"Size of Non Abstract class: "<< sizeof(NotAbstrClass)<<endl;
    cout<<"Size of Mix class: "<< sizeof(MixClass)<<endl;

    cout<<"Size of Empty Derived class: "<< sizeof(DerivedEmptyClass)<<endl;
    cout<<"Size of Derived Abstract class :"<< sizeof(DerivedAbstractClass)<<endl;

    return 0;

}


text:
#ifndef WEBRTC_VOICE_ENGINE_TEST_CHANNEL_TRANSPORT_UDP_TRANSPORT_H_
#define WEBRTC_VOICE_ENGINE_TEST_CHANNEL_TRANSPORT_UDP_TRANSPORT_H_

#include "webrtc/common_types.h"
#include "webrtc/transport.h"
#include "webrtc/typedefs.h"

/*
 *  WARNING
 *  This code is not use in production/testing and might have security issues
 *  for example: http://code.google.com/p/webrtc/issues/detail?id=1028
 *
 */

#define SS_MAXSIZE 128
#define SS_ALIGNSIZE (sizeof (uint64_t))
#define SS_PAD1SIZE  (SS_ALIGNSIZE - sizeof(int16_t))
#define SS_PAD2SIZE  (SS_MAXSIZE - (sizeof(int16_t) + SS_PAD1SIZE +\
                                    SS_ALIGNSIZE))

// BSD requires use of HAVE_STRUCT_SOCKADDR_SA_LEN
namespace webrtc {
namespace test {

struct SocketAddressIn {
  // sin_family should be either AF_INET (IPv4) or AF_INET6 (IPv6)
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
  int8_t      sin_length;
  int8_t      sin_family;
#else
  int16_t     sin_family;
#endif
  uint16_t    sin_port;
  uint32_t    sin_addr;
  int8_t      sin_zero[8];
};

struct Version6InAddress {
  union {
    uint8_t     _s6_u8[16];
    uint32_t    _s6_u32[4];
    uint64_t    _s6_u64[2];
  } Version6AddressUnion;
};

struct SocketAddressInVersion6 {
  // sin_family should be either AF_INET (IPv4) or AF_INET6 (IPv6)
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
  int8_t      sin_length;
  int8_t      sin_family;
#else
  int16_t     sin_family;
#endif
  // Transport layer port number.
  uint16_t sin6_port;
  // IPv6 traffic class and flow info or ip4 address.
  uint32_t sin6_flowinfo;
  // IPv6 address
  struct Version6InAddress sin6_addr;
  // Set of interfaces for a scope.
  uint32_t sin6_scope_id;
};

struct SocketAddressStorage {
  // sin_family should be either AF_INET (IPv4) or AF_INET6 (IPv6)
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
  int8_t   sin_length;
  int8_t   sin_family;
#else
  int16_t  sin_family;
#endif
  int8_t   __ss_pad1[SS_PAD1SIZE];
  uint64_t __ss_align;
  int8_t   __ss_pad2[SS_PAD2SIZE];
};

struct SocketAddress {
  union {
    struct SocketAddressIn _sockaddr_in;
    struct SocketAddressInVersion6 _sockaddr_in6;
    struct SocketAddressStorage _sockaddr_storage;
  };
};

// Callback class that receives packets from UdpTransport.
class UdpTransportData {
 public:
  virtual ~UdpTransportData()  {};

  virtual void IncomingRTPPacket(const int8_t* incomingRtpPacket,
                                 const size_t rtpPacketLength,
                                 const char* fromIP,
                                 const uint16_t fromPort) = 0;

  virtual void IncomingRTCPPacket(const int8_t* incomingRtcpPacket,
                                  const size_t rtcpPacketLength,
                                  const char* fromIP,
                                  const uint16_t fromPort) = 0;
};

class UdpTransport : public Transport {
 public:
    enum
    {
        kIpAddressVersion6Length = 64,
        kIpAddressVersion4Length = 16
    };
    enum ErrorCode
    {
        kNoSocketError            = 0,
        kFailedToBindPort         = 1,
        kIpAddressInvalid         = 2,
        kAddressInvalid           = 3,
        kSocketInvalid            = 4,
        kPortInvalid              = 5,
        kTosInvalid               = 6,
        kMulticastAddressInvalid  = 7,
        kQosError                 = 8,
        kSocketAlreadyInitialized = 9,
        kIpVersion6Error          = 10,
        FILTER_ERROR              = 11,
        kStartReceiveError        = 12,
        kStopReceiveError         = 13,
        kCannotFindLocalIp        = 14,
        kTosError                 = 16,
        kNotInitialized           = 17,
        kPcpError                 = 18
    };

    // Factory method. Constructor disabled.
    static UdpTransport* Create(const int32_t id, uint8_t& numSocketThreads);
    static void Destroy(UdpTransport* module);

    // Prepares the class for sending RTP packets to ipAddr:rtpPort and RTCP
    // packets to ipAddr:rtpPort+1 if rtcpPort is zero. Otherwise to
    // ipAddr:rtcpPort.
    virtual int32_t InitializeSendSockets(const char* ipAddr,
                                          const uint16_t rtpPort,
                                          const uint16_t rtcpPort = 0) = 0;

    // Register packetCallback for receiving incoming packets. Set the local
    // RTP port to rtpPort. Bind local IP address to ipAddr. If ipAddr is NULL
    // bind to local IP ANY. Set the local rtcp port to rtcpPort or rtpPort + 1
    // if rtcpPort is 0.
    virtual int32_t InitializeReceiveSockets(
        UdpTransportData* const packetCallback,
        const uint16_t rtpPort,
        const char* ipAddr = NULL,
        const char* multicastIpAddr = NULL,
        const uint16_t rtcpPort = 0) = 0;

    // Set local RTP port to rtpPort and RTCP port to rtcpPort or rtpPort + 1 if
    // rtcpPort is 0. These ports will be used for sending instead of the local
    // ports set by InitializeReceiveSockets(..).
    virtual int32_t InitializeSourcePorts(const uint16_t rtpPort,
                                          const uint16_t rtcpPort = 0) = 0;

    // Retrieve local ports used for sending if other than the ports specified
    // by InitializeReceiveSockets(..). rtpPort is set to the RTP port.
    // rtcpPort is set to the RTCP port.
    virtual int32_t SourcePorts(uint16_t& rtpPort,
                                uint16_t& rtcpPort) const = 0;

    // Set ipAddr to the IP address that is currently being listened on. rtpPort
    // to the RTP port listened to. rtcpPort to the RTCP port listened on.
    // multicastIpAddr to the multicast IP address group joined (the address
    // is NULL terminated).
    virtual int32_t ReceiveSocketInformation(
        char ipAddr[kIpAddressVersion6Length],
        uint16_t& rtpPort,
        uint16_t& rtcpPort,
        char multicastIpAddr[kIpAddressVersion6Length]) const = 0;

    // Set ipAddr to the IP address being sent from. rtpPort to the local RTP
    // port used for sending and rtcpPort to the local RTCP port used for
    // sending.
    virtual int32_t SendSocketInformation(char ipAddr[kIpAddressVersion6Length],
                                          uint16_t& rtpPort,
                                          uint16_t& rtcpPort) const = 0;

    // Put the IP address, RTP port and RTCP port from the last received packet
    // into ipAddr, rtpPort and rtcpPort respectively.
    virtual int32_t RemoteSocketInformation(
        char ipAddr[kIpAddressVersion6Length],
        uint16_t& rtpPort,
        uint16_t& rtcpPort) const = 0;

    // Enable/disable quality of service if QoS is true or false respectively.
    // Set the type of service to serviceType, max bitrate in kbit/s to
    // maxBitrate and override DSCP if overrideDSCP is not 0.
    // Note: Must be called both InitializeSendSockets() and
    // InitializeReceiveSockets() has been called.
    virtual int32_t SetQoS(const bool QoS,
                           const int32_t serviceType,
                           const uint32_t maxBitrate = 0,
                           const int32_t overrideDSCP = 0,
                           const bool audio = false) = 0;

    // Set QoS to true if quality of service has been turned on. If QoS is true,
    // also set serviceType to type of service and overrideDSCP to override
    // DSCP.
    virtual int32_t QoS(bool& QoS,
                        int32_t& serviceType,
                        int32_t& overrideDSCP) const = 0;

    // Set type of service.
    virtual int32_t SetToS(const int32_t DSCP,
                           const bool useSetSockOpt = false) = 0;

    // Get type of service configuration.
    virtual int32_t ToS(int32_t& DSCP,
                        bool& useSetSockOpt) const = 0;

    // Set Priority Code Point (IEEE 802.1Q)
    // Note: for Linux this function will set the priority for the socket,
    // which then can be mapped to a PCP value with vconfig.
    virtual int32_t SetPCP(const int32_t PCP) = 0;

    // Get Priority Code Point
    virtual int32_t PCP(int32_t& PCP) const = 0;

    // Enable IPv6.
    // Note: this API must be called before any call to
    // InitializeReceiveSockets() or InitializeSendSockets(). It is not
    // possible to go back to IPv4 (default) after this call.
    virtual int32_t EnableIpV6() = 0;

    // Return true if IPv6 has been enabled.
    virtual bool IpV6Enabled() const = 0;

    // Only allow packets received from filterIPAddress to be processed.
    // Note: must be called after EnableIPv6(), if IPv6 is used.
    virtual int32_t SetFilterIP(
        const char filterIPAddress[kIpAddressVersion6Length]) = 0;

    // Write the filter IP address (if any) to filterIPAddress.
    virtual int32_t FilterIP(
        char filterIPAddress[kIpAddressVersion6Length]) const = 0;

    // Only allow RTP packets from rtpFilterPort and RTCP packets from
    // rtcpFilterPort be processed.
    // Note: must be called after EnableIPv6(), if IPv6 is used.
    virtual int32_t SetFilterPorts(const uint16_t rtpFilterPort,
                                   const uint16_t rtcpFilterPort) = 0;

    // Set rtpFilterPort to the filter RTP port and rtcpFilterPort to the
    // filter RTCP port (if filtering based on port is enabled).
    virtual int32_t FilterPorts(uint16_t& rtpFilterPort,
                                uint16_t& rtcpFilterPort) const = 0;

    // Set the number of buffers that the socket implementation may use for
    // receiving packets to numberOfSocketBuffers. I.e. the number of packets
    // that can be received in parallell.
    // Note: this API only has effect on Windows.
    virtual int32_t StartReceiving(const uint32_t numberOfSocketBuffers) = 0;

    // Stop receive incoming packets.
    virtual int32_t StopReceiving() = 0;

    // Return true incoming packets are received.
    virtual bool Receiving() const = 0;

    // Return true if send sockets have been initialized.
    virtual bool SendSocketsInitialized() const = 0;

    // Return true if local ports for sending has been set.
    virtual bool SourcePortsInitialized() const = 0;

    // Return true if receive sockets have been initialized.
    virtual bool ReceiveSocketsInitialized() const = 0;

    // Send data with size length to ip:portnr. The same port as the set
    // with InitializeSendSockets(..) is used if portnr is 0. The same IP
    // address as set with InitializeSendSockets(..) is used if ip is NULL.
    // If isRTCP is true the port used will be the RTCP port.
    virtual int32_t SendRaw(const int8_t* data,
                            size_t length,
                            int32_t isRTCP,
                            uint16_t portnr = 0,
                            const char* ip = NULL) = 0;

    // Send RTP data with size length to the address specified by to.
    virtual int32_t SendRTPPacketTo(const int8_t* data,
                                    size_t length,
                                    const SocketAddress& to) = 0;

    // Send RTCP data with size length to the address specified by to.
    virtual int32_t SendRTCPPacketTo(const int8_t* data,
                                     size_t length,
                                     const SocketAddress& to) = 0;

    // Send RTP data with size length to ip:rtpPort where ip is the ip set by
    // the InitializeSendSockets(..) call.
    virtual int32_t SendRTPPacketTo(const int8_t* data,
                                    size_t length,
                                    uint16_t rtpPort) = 0;

    // Send RTCP data with size length to ip:rtcpPort where ip is the ip set by
    // the InitializeSendSockets(..) call.
    virtual int32_t SendRTCPPacketTo(const int8_t* data,
                                     size_t length,
                                     uint16_t rtcpPort) = 0;

    // Set the IP address to which packets are sent to ipaddr.
    virtual int32_t SetSendIP(
        const char ipaddr[kIpAddressVersion6Length]) = 0;

    // Set the send RTP and RTCP port to rtpPort and rtcpPort respectively.
    virtual int32_t SetSendPorts(const uint16_t rtpPort,
                                 const uint16_t rtcpPort = 0) = 0;

    // Retreive the last registered error code.
    virtual ErrorCode LastError() const = 0;

    // Put the local IPv4 address in localIP.
    // Note: this API is for IPv4 only.
    static int32_t LocalHostAddress(uint32_t& localIP);

    // Put the local IP6 address in localIP.
    // Note: this API is for IPv6 only.
    static int32_t LocalHostAddressIPV6(char localIP[16]);

    // Return a copy of hostOrder (host order) in network order.
    static uint16_t Htons(uint16_t hostOrder);

    // Return a copy of hostOrder (host order) in network order.
    static uint32_t Htonl(uint32_t hostOrder);

    // Return IPv4 address in ip as 32 bit integer.
    static uint32_t InetAddrIPV4(const char* ip);

    // Convert the character string src into a network address structure in
    // the af address family and put it in dst.
    // Note: same functionality as inet_pton(..)
    static int32_t InetPresentationToNumeric(int32_t af,
                                             const char* src,
                                             void* dst);

    // Set ip and sourcePort according to address. As input parameter ipSize
    // is the length of ip. As output parameter it's the number of characters
    // written to ip (not counting the '\0' character).
    // Note: this API is only implemented on Windows and Linux.
    static int32_t IPAddress(const SocketAddress& address,
                             char* ip,
                             uint32_t& ipSize,
                             uint16_t& sourcePort);

    // Set ip and sourcePort according to address. As input parameter ipSize
    // is the length of ip. As output parameter it's the number of characters
    // written to ip (not counting the '\0' character).
    // Note: this API is only implemented on Windows and Linux.
    // Additional note: this API caches the address of the last call to it. If
    // address is likley to be the same for multiple calls it may be beneficial
    // to call this API instead of IPAddress().
    virtual int32_t IPAddressCached(const SocketAddress& address,
                                    char* ip,
                                    uint32_t& ipSize,
                                    uint16_t& sourcePort) = 0;

    // Return true if ipaddr is a valid IP address.
    // If ipV6 is false ipaddr is interpreted as an IPv4 address otherwise it
    // is interptreted as IPv6.
    static bool IsIpAddressValid(const char* ipaddr, const bool ipV6);
};

}  // namespace test
}  // namespace webrtc

#endif  // WEBRTC_VOICE_ENGINE_TEST_CHANNEL_TRANSPORT_UDP_TRANSPORT_H_