text:
#region License

#endregion License

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace Trame.Math
{
    [Serializable]
    public struct Vector3 : IEquatable<Vector3>
    {
        #region Private Fields

        private static  Vector3 zero = new Vector3(0f, 0f, 0f);
        private static  Vector3 one = new Vector3(1f, 1f, 1f);
        private static  Vector3 unitX = new Vector3(1f, 0f, 0f);
        private static  Vector3 unitY = new Vector3(0f, 1f, 0f);
        private static  Vector3 unitZ = new Vector3(0f, 0f, 1f);
        private static  Vector3 up = new Vector3(0f, 1f, 0f);
        private static  Vector3 down = new Vector3(0f, -1f, 0f);
        private static  Vector3 right = new Vector3(1f, 0f, 0f);
        private static Vector3 left = new Vector3(-1f, 0f, 0f);
        private static Vector3 forward = new Vector3(0f, 0f, -1f);
        private static Vector3 backward = new Vector3(0f, 0f, 1f);

        #endregion Private Fields

        #region Public Fields

        public double X;
        public double Y;
        public double Z;

        #endregion Public Fields

        #region Properties

        public static Vector3 Zero
        {
            get { return zero; }
        }

        public static Vector3 One
        {
            get { return one; }
        }

        public static Vector3 UnitX
        {
            get { return unitX; }
        }

        public static Vector3 UnitY
        {
            get { return unitY; }
        }

        public static Vector3 UnitZ
        {
            get { return unitZ; }
        }

        public static Vector3 Up
        {
            get { return up; }
        }

        public static Vector3 Down
        {
            get { return down; }
        }

        public static Vector3 Right
        {
            get { return right; }
        }

        public static Vector3 Left
        {
            get { return left; }
        }

        public static Vector3 Forward
        {
            get { return forward; }
        }

        public static Vector3 Backward
        {
            get { return backward; }
        }

        #endregion Properties

        #region Constructors

        public Vector3(double x, double y, double z)
        {
            this.X = x;
            this.Y = y;
            this.Z = z;
        }

        public Vector3(double value)
        {
            this.X = value;
            this.Y = value;
            this.Z = value;
        }

        public Vector3(Vector2 value, double z)
        {
            this.X = value.X;
            this.Y = value.Y;
            this.Z = z;
        }

        #endregion Constructors

        #region Public Methods

        public static Vector3 Add(Vector3 value1, Vector3 value2)
        {
            value1.X += value2.X;
            value1.Y += value2.Y;
            value1.Z += value2.Z;
            return value1;
        }

        public static void Add(ref Vector3 value1, ref Vector3 value2, out Vector3 result)
        {
            result.X = value1.X + value2.X;
            result.Y = value1.Y + value2.Y;
            result.Z = value1.Z + value2.Z;
        }

        public static Vector3 Barycentric(Vector3 value1, Vector3 value2, Vector3 value3, double amount1, double amount2)
        {
            return new Vector3(
                MathHelper.Barycentric(value1.X, value2.X, value3.X, amount1, amount2),
                MathHelper.Barycentric(value1.Y, value2.Y, value3.Y, amount1, amount2),
                MathHelper.Barycentric(value1.Z, value2.Z, value3.Z, amount1, amount2));
        }

        public static void Barycentric(ref Vector3 value1, ref Vector3 value2, ref Vector3 value3, double amount1, double amount2, out Vector3 result)
        {
            result = new Vector3(
                MathHelper.Barycentric(value1.X, value2.X, value3.X, amount1, amount2),
                MathHelper.Barycentric(value1.Y, value2.Y, value3.Y, amount1, amount2),
                MathHelper.Barycentric(value1.Z, value2.Z, value3.Z, amount1, amount2));
        }

        public static Vector3 CatmullRom(Vector3 value1, Vector3 value2, Vector3 value3, Vector3 value4, double amount)
        {
            return new Vector3(
                MathHelper.CatmullRom(value1.X, value2.X, value3.X, value4.X, amount),
                MathHelper.CatmullRom(value1.Y, value2.Y, value3.Y, value4.Y, amount),
                MathHelper.CatmullRom(value1.Z, value2.Z, value3.Z, value4.Z, amount));
        }

        public static void CatmullRom(ref Vector3 value1, ref Vector3 value2, ref Vector3 value3, ref Vector3 value4, double amount, out Vector3 result)
        {
            result = new Vector3(
                MathHelper.CatmullRom(value1.X, value2.X, value3.X, value4.X, amount),
                MathHelper.CatmullRom(value1.Y, value2.Y, value3.Y, value4.Y, amount),
                MathHelper.CatmullRom(value1.Z, value2.Z, value3.Z, value4.Z, amount));
        }

        public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max)
        {
            return new Vector3(
                MathHelper.Clamp(value1.X, min.X, max.X),
                MathHelper.Clamp(value1.Y, min.Y, max.Y),
                MathHelper.Clamp(value1.Z, min.Z, max.Z));
        }

        public static void Clamp(ref Vector3 value1, ref Vector3 min, ref Vector3 max, out Vector3 result)
        {
            result = new Vector3(
                MathHelper.Clamp(value1.X, min.X, max.X),
                MathHelper.Clamp(value1.Y, min.Y, max.Y),
                MathHelper.Clamp(value1.Z, min.Z, max.Z));
        }

        public static Vector3 Cross(Vector3 vector1, Vector3 vector2)
        {
            Cross(ref vector1, ref vector2, out vector1);
            return vector1;
        }

        public static void Cross(ref Vector3 vector1, ref Vector3 vector2, out Vector3 result)
        {
            result = new Vector3(vector1.Y * vector2.Z - vector2.Y * vector1.Z,
                                 -(vector1.X * vector2.Z - vector2.X * vector1.Z),
                                 vector1.X * vector2.Y - vector2.X * vector1.Y);
        }

        public static double Distance(Vector3 vector1, Vector3 vector2)
        {
            double result;
            DistanceSquared(ref vector1, ref vector2, out result);
            return (double)System.Math.Sqrt(result);
        }

        public static void Distance(ref Vector3 value1, ref Vector3 value2, out double result)
        {
            DistanceSquared(ref value1, ref value2, out result);
            result = (double)System.Math.Sqrt(result);
        }

        public static double DistanceSquared(Vector3 value1, Vector3 value2)
        {
            double result;
            DistanceSquared(ref value1, ref value2, out result);
            return result;
        }

        public static void DistanceSquared(ref Vector3 value1, ref Vector3 value2, out double result)
        {
            result = (value1.X - value2.X) * (value1.X - value2.X) +
                     (value1.Y - value2.Y) * (value1.Y - value2.Y) +
                     (value1.Z - value2.Z) * (value1.Z - value2.Z);
        }

        public static Vector3 Divide(Vector3 value1, Vector3 value2)
        {
            value1.X /= value2.X;
            value1.Y /= value2.Y;
            value1.Z /= value2.Z;
            return value1;
        }

        public static Vector3 Divide(Vector3 value1, double value2)
        {
            double factor = 1 / value2;
            value1.X *= factor;
            value1.Y *= factor;
            value1.Z *= factor;
            return value1;
        }

        public static void Divide(ref Vector3 value1, double divisor, out Vector3 result)
        {
            double factor = 1 / divisor;
            result.X = value1.X * factor;
            result.Y = value1.Y * factor;
            result.Z = value1.Z * factor;
        }

        public static void Divide(ref Vector3 value1, ref Vector3 value2, out Vector3 result)
        {
            result.X = value1.X / value2.X;
            result.Y = value1.Y / value2.Y;
            result.Z = value1.Z / value2.Z;
        }

        public static double Dot(Vector3 vector1, Vector3 vector2)
        {
            return vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z;
        }

        public static void Dot(ref Vector3 vector1, ref Vector3 vector2, out double result)
        {
            result = vector1.X * vector2.X + vector1.Y * vector2.Y + vector1.Z * vector2.Z;
        }

        public override bool Equals(object obj)
        {
            return (obj is Vector3) ? this == (Vector3)obj : false;
        }

        public bool Equals(Vector3 other)
        {
            return this == other;
        }

        public override int GetHashCode()
        {
            return (int)(this.X + this.Y + this.Z);
        }

        public static Vector3 Hermite(Vector3 value1, Vector3 tangent1, Vector3 value2, Vector3 tangent2, double amount)
        {
            Vector3 result = new Vector3();
            Hermite(ref value1, ref tangent1, ref value2, ref tangent2, amount, out result);
            return result;
        }

        public static void Hermite(ref Vector3 value1, ref Vector3 tangent1, ref Vector3 value2, ref Vector3 tangent2, double amount, out Vector3 result)
        {
            result.X = MathHelper.Hermite(value1.X, tangent1.X, value2.X, tangent2.X, amount);
            result.Y = MathHelper.Hermite(value1.Y, tangent1.Y, value2.Y, tangent2.Y, amount);
            result.Z = MathHelper.Hermite(value1.Z, tangent1.Z, value2.Z, tangent2.Z, amount);
        }

        public double Length()
        {
            double result;
            DistanceSquared(ref this, ref zero, out result);
            return (double)System.Math.Sqrt(result);
        }

        public double LengthSquared()
        {
            double result;
            DistanceSquared(ref this, ref zero, out result);
            return result;
        }

        public static Vector3 Lerp(Vector3 value1, Vector3 value2, double amount)
        {
            return new Vector3(
                MathHelper.Lerp(value1.X, value2.X, amount),
                MathHelper.Lerp(value1.Y, value2.Y, amount),
                MathHelper.Lerp(value1.Z, value2.Z, amount));
        }

        public static void Lerp(ref Vector3 value1, ref Vector3 value2, double amount, out Vector3 result)
        {
            result = new Vector3(
                MathHelper.Lerp(value1.X, value2.X, amount),
                MathHelper.Lerp(value1.Y, value2.Y, amount),
                MathHelper.Lerp(value1.Z, value2.Z, amount));
        }

        public static Vector3 Max(Vector3 value1, Vector3 value2)
        {
            return new Vector3(
                MathHelper.Max(value1.X, value2.X),
                MathHelper.Max(value1.Y, value2.Y),
                MathHelper.Max(value1.Z, value2.Z));
        }

        public static void Max(ref Vector3 value1, ref Vector3 value2, out Vector3 result)
        {
            result = new Vector3(
                MathHelper.Max(value1.X, value2.X),
                MathHelper.Max(value1.Y, value2.Y),
                MathHelper.Max(value1.Z, value2.Z));
        }

        public static Vector3 Min(Vector3 value1, Vector3 value2)
        {
            return new Vector3(
                MathHelper.Min(value1.X, value2.X),
                MathHelper.Min(value1.Y, value2.Y),
                MathHelper.Min(value1.Z, value2.Z));
        }

        public static void Min(ref Vector3 value1, ref Vector3 value2, out Vector3 result)
        {
            result = new Vector3(
                MathHelper.Min(value1.X, value2.X),
                MathHelper.Min(value1.Y, value2.Y),
                MathHelper.Min(value1.Z, value2.Z));
        }

        public static Vector3 Multiply(Vector3 value1, Vector3 value2)
        {
            value1.X *= value2.X;
            value1.Y *= value2.Y;
            value1.Z *= value2.Z;
            return value1;
        }

        public static Vector3 Multiply(Vector3 value1, double scaleFactor)
        {
            value1.X *= scaleFactor;
            value1.Y *= scaleFactor;
            value1.Z *= scaleFactor;
            return value1;
        }

        public static void Multiply(ref Vector3 value1, double scaleFactor, out Vector3 result)
        {
            result.X = value1.X * scaleFactor;
            result.Y = value1.Y * scaleFactor;
            result.Z = value1.Z * scaleFactor;
        }

        public static void Multiply(ref Vector3 value1, ref Vector3 value2, out Vector3 result)
        {
            result.X = value1.X * value2.X;
            result.Y = value1.Y * value2.Y;
            result.Z = value1.Z * value2.Z;
        }

        public static Vector3 Negate(Vector3 value)
        {
            value = new Vector3(-value.X, -value.Y, -value.Z);
            return value;
        }

        public static void Negate(ref Vector3 value, out Vector3 result)
        {
            result = new Vector3(-value.X, -value.Y, -value.Z);
        }

        public void Normalize()
        {
            Normalize(ref this, out this);
        }

        public static Vector3 Normalize(Vector3 vector)
        {
            Normalize(ref vector, out vector);
            return vector;
        }

        public static void Normalize(ref Vector3 value, out Vector3 result)
        {
            double factor;
            Distance(ref value, ref zero, out factor);
            factor = 1f / factor;
            result.X = value.X * factor;
            result.Y = value.Y * factor;
            result.Z = value.Z * factor;
        }

	public static Vector3 Reflect(Vector3 vector, Vector3 normal)
	{
		// I is the original array
		// N is the normal of the incident plane
		// R = I - (2 * N * ( DotProduct[ I,N] ))
		Vector3 reflectedVector;
		// inline the dotProduct here instead of calling method
		double dotProduct = ((vector.X * normal.X) + (vector.Y * normal.Y)) + (vector.Z * normal.Z);
		reflectedVector.X = vector.X - (2.0f * normal.X) * dotProduct;
		reflectedVector.Y = vector.Y - (2.0f * normal.Y) * dotProduct;
		reflectedVector.Z = vector.Z - (2.0f * normal.Z) * dotProduct;

		return reflectedVector;
	}

	public static void Reflect(ref Vector3 vector, ref Vector3 normal, out Vector3 result)
	{
		// I is the original array
		// N is the normal of the incident plane
		// R = I - (2 * N * ( DotProduct[ I,N] ))

		// inline the dotProduct here instead of calling method
		double dotProduct = ((vector.X * normal.X) + (vector.Y * normal.Y)) + (vector.Z * normal.Z);
		result.X = vector.X - (2.0f * normal.X) * dotProduct;
		result.Y = vector.Y - (2.0f * normal.Y) * dotProduct;
		result.Z = vector.Z - (2.0f * normal.Z) * dotProduct;

	}

        public static Vector3 SmoothStep(Vector3 value1, Vector3 value2, double amount)
        {
            return new Vector3(
                MathHelper.SmoothStep(value1.X, value2.X, amount),
                MathHelper.SmoothStep(value1.Y, value2.Y, amount),
                MathHelper.SmoothStep(value1.Z, value2.Z, amount));
        }

        public static void SmoothStep(ref Vector3 value1, ref Vector3 value2, double amount, out Vector3 result)
        {
            result = new Vector3(
                MathHelper.SmoothStep(value1.X, value2.X, amount),
                MathHelper.SmoothStep(value1.Y, value2.Y, amount),
                MathHelper.SmoothStep(value1.Z, value2.Z, amount));
        }

        public static Vector3 Subtract(Vector3 value1, Vector3 value2)
        {
            value1.X -= value2.X;
            value1.Y -= value2.Y;
            value1.Z -= value2.Z;
            return value1;
        }

        public static void Subtract(ref Vector3 value1, ref Vector3 value2, out Vector3 result)
        {
            result.X = value1.X - value2.X;
            result.Y = value1.Y - value2.Y;
            result.Z = value1.Z - value2.Z;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder(32);
            sb.Append("{X:");
            sb.Append(this.X);
            sb.Append(" Y:");
            sb.Append(this.Y);
            sb.Append(" Z:");
            sb.Append(this.Z);
            sb.Append("}");
            return sb.ToString();
        }

        public static Vector3 Transform(Vector3 position, Matrix matrix)
        {
            Transform(ref position, ref matrix, out position);
            return position;
        }

        public static void Transform(ref Vector3 position, ref Matrix matrix, out Vector3 result)
        {
            result = new Vector3((position.X * matrix.M11) + (position.Y * matrix.M21) + (position.Z * matrix.M31) + matrix.M41,
                                 (position.X * matrix.M12) + (position.Y * matrix.M22) + (position.Z * matrix.M32) + matrix.M42,
                                 (position.X * matrix.M13) + (position.Y * matrix.M23) + (position.Z * matrix.M33) + matrix.M43);
        }

        public static void Transform(Vector3[] sourceArray, ref Matrix matrix, Vector3[] destinationArray)
        {
            Debug.Assert(destinationArray.Length >= sourceArray.Length, "The destination array is smaller than the source array.");

            // TODO: Are there options on some platforms to implement a vectorized version of this?

            for (var i = 0; i < sourceArray.Length; i++)
            {
                var position = sourceArray[i];
                destinationArray[i] =
                    new Vector3(
                        (position.X*matrix.M11) + (position.Y*matrix.M21) + (position.Z*matrix.M31) + matrix.M41,
                        (position.X*matrix.M12) + (position.Y*matrix.M22) + (position.Z*matrix.M32) + matrix.M42,
                        (position.X*matrix.M13) + (position.Y*matrix.M23) + (position.Z*matrix.M33) + matrix.M43);
            }
        }

        public static double Angle(Vector3 a, Vector3 b)
        {
            var aLen = a.Length();
            var bLen = b.Length();

            if (bLen == 0 || bLen == 0)
            {
                return 0.0;
            }
            var cos = Vector3.Dot(a, b) / (aLen * bLen);

            return System.Math.Abs(cos) > 1.0 ? 0.0 : System.Math.Acos(cos);
        }

        /// <summary>
        /// Transforms a vector by a quaternion rotation.
        /// </summary>
        /// <param name="vec">The vector to transform.</param>
        /// <param name="quat">The quaternion to rotate the vector by.</param>
        /// <returns>The result of the operation.</returns>
        public static Vector3 Transform(Vector3 vec, Quaternion quat)
        {
            Vector3 result;
            Transform(ref vec, ref quat, out result);
            return result;
        }

        /// <summary>
        /// Transforms a vector by a quaternion rotation.
        /// </summary>
        /// <param name="vec">The vector to transform.</param>
        /// <param name="quat">The quaternion to rotate the vector by.</param>
        /// <param name="result">The result of the operation.</param>
//        public static void Transform(ref Vector3 vec, ref Quaternion quat, out Vector3 result)
//        {
//		// Taken from the OpentTK implementation of Vector3
//            // Since vec.W == 0, we can optimize quat * vec * quat^-1 as follows:
//            // vec + 2.0 * cross(quat.xyz, cross(quat.xyz, vec) + quat.w * vec)
//            Vector3 xyz = quat.Xyz, temp, temp2;
//            Vector3.Cross(ref xyz, ref vec, out temp);
//            Vector3.Multiply(ref vec, quat.W, out temp2);
//            Vector3.Add(ref temp, ref temp2, out temp);
//            Vector3.Cross(ref xyz, ref temp, out temp);
//            Vector3.Multiply(ref temp, 2, out temp);
//            Vector3.Add(ref vec, ref temp, out result);
//        }

        /// <summary>
        /// Transforms a vector by a quaternion rotation.
        /// </summary>
        /// <param name="vec">The vector to transform.</param>
        /// <param name="quat">The quaternion to rotate the vector by.</param>
        /// <param name="result">The result of the operation.</param>
        public static void Transform(ref Vector3 vec, ref Quaternion quat, out Vector3 result)
        {
			// This has not been tested
			// TODO:  This could probably be unrolled so will look into it later
			Matrix matrix = quat.ToMatrix();
			Transform(ref vec, ref matrix, out result);
        }

        public static Vector3 TransformNormal(Vector3 normal, Matrix matrix)
        {
            TransformNormal(ref normal, ref matrix, out normal);
            return normal;
        }

        public static void TransformNormal(ref Vector3 normal, ref Matrix matrix, out Vector3 result)
        {
            result = new Vector3((normal.X * matrix.M11) + (normal.Y * matrix.M21) + (normal.Z * matrix.M31),
                                 (normal.X * matrix.M12) + (normal.Y * matrix.M22) + (normal.Z * matrix.M32),
                                 (normal.X * matrix.M13) + (normal.Y * matrix.M23) + (normal.Z * matrix.M33));
        }

        #endregion Public methods

        #region Operators

        public static bool operator ==(Vector3 value1, Vector3 value2)
        {
            return value1.X == value2.X
                && value1.Y == value2.Y
                && value1.Z == value2.Z;
        }

        public static bool operator !=(Vector3 value1, Vector3 value2)
        {
            return !(value1 == value2);
        }

        public static Vector3 operator +(Vector3 value1, Vector3 value2)
        {
            value1.X += value2.X;
            value1.Y += value2.Y;
            value1.Z += value2.Z;
            return value1;
        }

        public static Vector3 operator -(Vector3 value)
        {
            value = new Vector3(-value.X, -value.Y, -value.Z);
            return value;
        }

        public static Vector3 operator -(Vector3 value1, Vector3 value2)
        {
            value1.X -= value2.X;
            value1.Y -= value2.Y;
            value1.Z -= value2.Z;
            return value1;
        }

        public static Vector3 operator *(Vector3 value1, Vector3 value2)
        {
            value1.X *= value2.X;
            value1.Y *= value2.Y;
            value1.Z *= value2.Z;
            return value1;
        }

        public static Vector3 operator *(Vector3 value, double scaleFactor)
        {
            value.X *= scaleFactor;
            value.Y *= scaleFactor;
            value.Z *= scaleFactor;
            return value;
        }

        public static Vector3 operator *(double scaleFactor, Vector3 value)
        {
            value.X *= scaleFactor;
            value.Y *= scaleFactor;
            value.Z *= scaleFactor;
            return value;
        }

        public static Vector3 operator /(Vector3 value1, Vector3 value2)
        {
            value1.X /= value2.X;
            value1.Y /= value2.Y;
            value1.Z /= value2.Z;
            return value1;
        }

        public static Vector3 operator /(Vector3 value, double divider)
        {
            double factor = 1 / divider;
            value.X *= factor;
            value.Y *= factor;
            value.Z *= factor;
            return value;
        }

        #endregion

        public IEnumerable<float> ToArray()
        {
            return new float[]{(float) X, (float) Y, (float) Z};
        }

        public static Vector3 FromList(List<float> l)
        {
            return l.Count >= 3 ? new Vector3(l[0], l[1], l[2]) : new Vector3(0);
        }
    }
}


text:
/*	$NetBSD: loc_ntoa.c,v 1.3 2014/03/01 03:24:35 christos Exp $	*/

/* Stolen from BIND */

/*
 * Copyright (c) 1985
 *    The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies, and that
 * the name of Digital Equipment Corporation not be used in advertising or
 * publicity pertaining to distribution of the document or software without
 * specific, written prior permission.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

/*
 * Portions Copyright (c) 1995 by International Business Machines, Inc.
 *
 * International Business Machines, Inc. (hereinafter called IBM) grants
 * permission under its copyrights to use, copy, modify, and distribute this
 * Software with or without fee, provided that the above copyright notice and
 * all paragraphs of this notice appear in all copies, and that the name of IBM
 * not be used in connection with the marketing of any product incorporating
 * the Software or modifications thereof, without specific, written prior
 * permission.
 *
 * To the extent it has a right to do so, IBM grants an immunity from suit
 * under its patents, if any, for the use, sale or manufacture of products to
 * the extent that such products are used for performing Domain Name System
 * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
 * granted for any product per se or for any other function of any product.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
 * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
 * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
 */

/*
 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>

#include <ctype.h>
#include <errno.h>
#include <math.h>
#include <netdb.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "loc.h"

const char *precsize_ntoa();

/* takes an on-the-wire LOC RR and formats it in a human readable format. */
const char *
loc_ntoa(binary, ascii)
	const u_char *binary;
	char *ascii;
{
	static char *error = "?";
	static char tmpbuf[sizeof
"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
	const u_char *cp = binary;

	int latdeg, latmin, latsec, latsecfrac;
	int longdeg, longmin, longsec, longsecfrac;
	char northsouth, eastwest;
	int altmeters, altfrac, altsign;

	const u_int32_t referencealt = 100000 * 100;

	int32_t latval, longval, altval;
	u_int32_t templ;
	u_int8_t sizeval, hpval, vpval, versionval;

	char *sizestr, *hpstr, *vpstr;

	versionval = *cp++;

	if (ascii == NULL)
		ascii = tmpbuf;

	if (versionval) {
		(void) sprintf(ascii, "; error: unknown LOC RR version");
		return (ascii);
	}

	sizeval = *cp++;

	hpval = *cp++;
	vpval = *cp++;

	GETLONG(templ, cp);
	latval = (templ - ((unsigned)1<<31));

	GETLONG(templ, cp);
	longval = (templ - ((unsigned)1<<31));

	GETLONG(templ, cp);
	if (templ < referencealt) { /* below WGS 84 spheroid */
		altval = referencealt - templ;
		altsign = -1;
	} else {
		altval = templ - referencealt;
		altsign = 1;
	}

	if (latval < 0) {
		northsouth = 'S';
		latval = -latval;
	} else
		northsouth = 'N';

	latsecfrac = latval % 1000;
	latval = latval / 1000;
	latsec = latval % 60;
	latval = latval / 60;
	latmin = latval % 60;
	latval = latval / 60;
	latdeg = latval;

	if (longval < 0) {
		eastwest = 'W';
		longval = -longval;
	} else
		eastwest = 'E';

	longsecfrac = longval % 1000;
	longval = longval / 1000;
	longsec = longval % 60;
	longval = longval / 60;
	longmin = longval % 60;
	longval = longval / 60;
	longdeg = longval;

	altfrac = altval % 100;
	altmeters = (altval / 100) * altsign;

	if ((sizestr = strdup(precsize_ntoa(sizeval))) == NULL)
		sizestr = error;
	if ((hpstr = strdup(precsize_ntoa(hpval))) == NULL)
		hpstr = error;
	if ((vpstr = strdup(precsize_ntoa(vpval))) == NULL)
		vpstr = error;

	sprintf(ascii,
	      "%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %d.%.2dm %sm %sm %sm",
		latdeg, latmin, latsec, latsecfrac, northsouth,
		longdeg, longmin, longsec, longsecfrac, eastwest,
		altmeters, altfrac, sizestr, hpstr, vpstr);

	if (sizestr != error)
		free(sizestr);
	if (hpstr != error)
		free(hpstr);
	if (vpstr != error)
		free(vpstr);

	return (ascii);
}

static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
				      1000000,10000000,100000000,1000000000};

/* takes an XeY precision/size value, returns a string representation. */
const char *
precsize_ntoa(prec)
	u_int8_t prec;
{
	static char retbuf[sizeof "90000000.00"];	/* XXX nonreentrant */
	unsigned long val;
	int mantissa, exponent;

	mantissa = (int)((prec >> 4) & 0x0f) % 10;
	exponent = (int)((prec >> 0) & 0x0f) % 10;

	val = mantissa * poweroften[exponent];

	(void) sprintf(retbuf, "%ld.%.2ld", val/100, val%100);
	return (retbuf);
}

redpajama_set_name: RedPajamaGithub


text:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using Azure.AI.FormRecognizer.Training;

namespace Azure.AI.FormRecognizer.Models
{
    /// <summary>
    /// A factory that builds Azure.AI.FormRecognizer model types used for mocking.
    /// </summary>
    public static class FormRecognizerModelFactory
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Training.AccountProperties"/> class.
        /// </summary>
        /// <param name="customModelCount">The current count of trained custom models.</param>
        /// <param name="customModelLimit">The maximum number of models that can be trained for this account.</param>
        /// <returns>A new <see cref="Training.AccountProperties"/> instance for mocking.</returns>
        public static AccountProperties AccountProperties(int customModelCount, int customModelLimit) =>
            new AccountProperties(customModelCount, customModelLimit);

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FieldBoundingBox"/> structure.
        /// </summary>
        /// <param name="points">The sequence of points defining this <see cref="FormRecognizer.Models.FieldBoundingBox"/>.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FieldBoundingBox"/> instance for mocking.</returns>
        public static FieldBoundingBox FieldBoundingBox(IReadOnlyList<PointF> points) =>
            new FieldBoundingBox(points);

        /// <summary>
        /// Initializes a new instance of the <see cref="Training.CustomFormModel"/> class.
        /// </summary>
        /// <param name="modelId">The unique identifier of this model.</param>
        /// <param name="status">A status indicating this model's readiness for use.</param>
        /// <param name="trainingStartedOn">The date and time (UTC) when model training was started.</param>
        /// <param name="trainingCompletedOn">The date and time (UTC) when model training completed.</param>
        /// <param name="submodels">A list of submodels that are part of this model, each of which can recognize and extract fields from a different type of form.</param>
        /// <param name="trainingDocuments">A list of meta-data about each of the documents used to train the model.</param>
        /// <param name="errors">A list of errors occurred during the training operation.</param>
        /// <returns>A new <see cref="Training.CustomFormModel"/> instance for mocking.</returns>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static CustomFormModel CustomFormModel(string modelId, CustomFormModelStatus status, DateTimeOffset trainingStartedOn, DateTimeOffset trainingCompletedOn, IReadOnlyList<CustomFormSubmodel> submodels, IReadOnlyList<TrainingDocumentInfo> trainingDocuments, IReadOnlyList<FormRecognizerError> errors) =>
            CustomFormModel(modelId, status, trainingStartedOn, trainingCompletedOn, submodels, trainingDocuments, errors, default, default);

        /// <summary>
        /// Initializes a new instance of the <see cref="Training.CustomFormModel"/> class.
        /// </summary>
        /// <param name="modelId">The unique identifier of this model.</param>
        /// <param name="status">A status indicating this model's readiness for use.</param>
        /// <param name="trainingStartedOn">The date and time (UTC) when model training was started.</param>
        /// <param name="trainingCompletedOn">The date and time (UTC) when model training completed.</param>
        /// <param name="submodels">A list of submodels that are part of this model, each of which can recognize and extract fields from a different type of form.</param>
        /// <param name="trainingDocuments">A list of meta-data about each of the documents used to train the model.</param>
        /// <param name="errors">A list of errors occurred during the training operation.</param>
        /// <param name="modelName">An optional, user-defined name to associate with your model.</param>
        /// <param name="properties">Model properties, like for example, if a model is composed.</param>
        /// <returns>A new <see cref="Training.CustomFormModel"/> instance for mocking.</returns>
        public static CustomFormModel CustomFormModel(
            string modelId,
            CustomFormModelStatus status,
            DateTimeOffset trainingStartedOn,
            DateTimeOffset trainingCompletedOn,
            IReadOnlyList<CustomFormSubmodel> submodels,
            IReadOnlyList<TrainingDocumentInfo> trainingDocuments,
            IReadOnlyList<FormRecognizerError> errors,
            string modelName,
            CustomFormModelProperties properties)
        {
            submodels = submodels?.ToList();
            trainingDocuments = trainingDocuments?.ToList();
            errors = errors?.ToList();

            return new CustomFormModel(modelId, status, trainingStartedOn, trainingCompletedOn, submodels, trainingDocuments, errors, modelName, properties);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Training.CustomFormModelField"/> class.
        /// </summary>
        /// <param name="name">Canonical name; uniquely identifies a field within the form.</param>
        /// <param name="label">The label of this field on the form.</param>
        /// <param name="accuracy">The estimated recognition accuracy for this field.</param>
        /// <returns>A new <see cref="Training.CustomFormModelField"/> instance for mocking.</returns>
        public static CustomFormModelField CustomFormModelField(string name, string label, float? accuracy) =>
            new CustomFormModelField(name, label, accuracy);

        /// <summary>
        /// Initializes a new instance of the <see cref="Training.CustomFormModelInfo"/> class.
        /// </summary>
        /// <param name="modelId">The unique identifier of the model.</param>
        /// <param name="trainingStartedOn">The date and time (UTC) when model training was started.</param>
        /// <param name="trainingCompletedOn">The date and time (UTC) when model training completed.</param>
        /// <param name="status">The status of the model.</param>
        /// <returns>A new <see cref="Training.CustomFormModelInfo"/> instance for mocking.</returns>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static CustomFormModelInfo CustomFormModelInfo(string modelId, DateTimeOffset trainingStartedOn, DateTimeOffset trainingCompletedOn, CustomFormModelStatus status) =>
            CustomFormModelInfo(modelId, trainingStartedOn, trainingCompletedOn, status, default, default);

        /// <summary>
        /// Initializes a new instance of the <see cref="Training.CustomFormModelInfo"/> class.
        /// </summary>
        /// <param name="modelId">The unique identifier of the model.</param>
        /// <param name="trainingStartedOn">The date and time (UTC) when model training was started.</param>
        /// <param name="trainingCompletedOn">The date and time (UTC) when model training completed.</param>
        /// <param name="status">The status of the model.</param>
        /// <param name="modelName">An optional, user-defined name to associate with your model.</param>
        /// <param name="properties">Model properties, like for example, if a model is composed.</param>
        /// <returns>A new <see cref="Training.CustomFormModelInfo"/> instance for mocking.</returns>
        public static CustomFormModelInfo CustomFormModelInfo(string modelId, DateTimeOffset trainingStartedOn, DateTimeOffset trainingCompletedOn, CustomFormModelStatus status, string modelName, CustomFormModelProperties properties) =>
            new CustomFormModelInfo(modelId, status, trainingStartedOn, trainingCompletedOn, modelName, properties);

        /// <summary>
        /// Initializes a new instance of the <see cref="Training.CustomFormModelProperties"/> class.
        /// </summary>
        /// <param name="isComposedModel">Indicates if the model is a composed model.</param>
        /// <returns>A new <see cref="Training.CustomFormModelProperties"/> instance for mocking.</returns>
        public static CustomFormModelProperties CustomFormModelProperties(bool isComposedModel) =>
            new CustomFormModelProperties(isComposedModel);

        /// <summary>
        /// Initializes a new instance of the <see cref="Training.CustomFormSubmodel"/> class.
        /// </summary>
        /// <param name="formType">The type of form this submodel recognizes.</param>
        /// <param name="accuracy">The mean of the accuracies of this model's <see cref="Training.CustomFormModelField"/> instances.</param>
        /// <param name="fields">A dictionary of the fields that this submodel will recognize from the input document.</param>
        /// <returns>A new <see cref="Training.CustomFormSubmodel"/> instance for mocking.</returns>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static CustomFormSubmodel CustomFormSubmodel(string formType, float? accuracy, IReadOnlyDictionary<string, CustomFormModelField> fields) =>
            CustomFormSubmodel(formType, accuracy, fields, default);

        /// <summary>
        /// Initializes a new instance of the <see cref="Training.CustomFormSubmodel"/> class.
        /// </summary>
        /// <param name="formType">The type of form this submodel recognizes.</param>
        /// <param name="accuracy">The mean of the accuracies of this model's <see cref="Training.CustomFormModelField"/> instances.</param>
        /// <param name="fields">A dictionary of the fields that this submodel will recognize from the input document.</param>
        /// <param name="modelId">he unique identifier of the submodel.</param>
        /// <returns>A new <see cref="Training.CustomFormSubmodel"/> instance for mocking.</returns>
        public static CustomFormSubmodel CustomFormSubmodel(string formType, float? accuracy, IReadOnlyDictionary<string, CustomFormModelField> fields, string modelId)
        {
            fields = fields?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

            return new CustomFormSubmodel(formType, accuracy, fields, modelId);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FieldData"/> class.
        /// </summary>
        /// <param name="boundingBox">The quadrilateral bounding box that outlines the text of this element.</param>
        /// <param name="pageNumber">The 1-based number of the page in which this element is present.</param>
        /// <param name="text">The text of this form element.</param>
        /// <param name="fieldElements">A list of references to the field elements constituting this data.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FieldData"/> instance for mocking.</returns>
        public static FieldData FieldData(FieldBoundingBox boundingBox, int pageNumber, string text, IReadOnlyList<FormElement> fieldElements)
        {
            fieldElements = fieldElements?.ToList();

            return new FieldData(boundingBox, pageNumber, text, fieldElements);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FieldValue"/> structure.
        /// </summary>
        /// <param name="value">The actual field value.</param>
        /// <returns>A new <see cref="FieldValue"/> instance for mocking.</returns>
        public static FieldValue FieldValueWithStringValueType(string value) =>
            new FieldValue(value, FieldValueType.String);

        /// <summary>
        /// Initializes a new instance of the <see cref="FieldValue"/> structure.
        /// </summary>
        /// <param name="value">The actual field value.</param>
        /// <returns>A new <see cref="FieldValue"/> instance for mocking.</returns>
        public static FieldValue FieldValueWithInt64ValueType(long value) =>
            new FieldValue(value);

        /// <summary>
        /// Initializes a new instance of the <see cref="FieldValue"/> structure.
        /// </summary>
        /// <param name="value">The actual field value.</param>
        /// <returns>A new <see cref="FieldValue"/> instance for mocking.</returns>
        public static FieldValue FieldValueWithFloatValueType(float value) =>
            new FieldValue(value);

        /// <summary>
        /// Initializes a new instance of the <see cref="FieldValue"/> structure.
        /// </summary>
        /// <param name="value">The actual field value.</param>
        /// <returns>A new <see cref="FieldValue"/> instance for mocking.</returns>
        public static FieldValue FieldValueWithDateValueType(DateTime value) =>
            new FieldValue(value);

        /// <summary>
        /// Initializes a new instance of the <see cref="FieldValue"/> structure.
        /// </summary>
        /// <param name="value">The actual field value.</param>
        /// <returns>A new <see cref="FieldValue"/> instance for mocking.</returns>
        public static FieldValue FieldValueWithTimeValueType(TimeSpan value) =>
            new FieldValue(value);

        /// <summary>
        /// Initializes a new instance of the <see cref="FieldValue"/> structure.
        /// </summary>
        /// <param name="value">The actual field value.</param>
        /// <returns>A new <see cref="FieldValue"/> instance for mocking.</returns>
        public static FieldValue FieldValueWithPhoneNumberValueType(string value) =>
            new FieldValue(value, FieldValueType.PhoneNumber);

        /// <summary>
        /// Initializes a new instance of the <see cref="FieldValue"/> structure.
        /// </summary>
        /// <param name="value">The actual field value.</param>
        /// <returns>A new <see cref="FieldValue"/> instance for mocking.</returns>
        public static FieldValue FieldValueWithListValueType(IReadOnlyList<FormField> value)
        {
            value = value?.ToList();

            return new FieldValue(value);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FieldValue"/> structure.
        /// </summary>
        /// <param name="value">The actual field value.</param>
        /// <returns>A new <see cref="FieldValue"/> instance for mocking.</returns>
        public static FieldValue FieldValueWithDictionaryValueType(IReadOnlyDictionary<string, FormField> value)
        {
            value = value?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

            return new FieldValue(value);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FieldValue"/> structure.
        /// </summary>
        /// <param name="value">The actual field value.</param>
        /// <returns>A new <see cref="FieldValue"/> instance for mocking.</returns>
        public static FieldValue FieldValueWithSelectionMarkValueType(SelectionMarkState value) =>
            new FieldValue(value);

        /// <summary>
        /// Initializes a new instance of the <see cref="FieldValue"/> structure.
        /// </summary>
        /// <param name="value">The actual field value.</param>
        /// <returns>A new <see cref="FieldValue"/> instance for mocking.</returns>
        public static FieldValue FieldValueWithCountryCodeValueType(string value) =>
            new FieldValue(value, FieldValueType.Country);

        /// <summary>
        /// Initializes a new instance of the <see cref="FieldValue"/> structure.
        /// </summary>
        /// <param name="value">The actual field value.</param>
        /// <returns>A new <see cref="FieldValue"/> instance for mocking.</returns>
        public static FieldValue FieldValueWithGenderValueType(FieldValueGender value) =>
            new FieldValue(value);

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FormField"/> class.
        /// </summary>
        /// <param name="name">Canonical name; uniquely identifies a field within the form.</param>
        /// <param name="labelData">Contains the text, bounding box and content of the label of the field in the form.</param>
        /// <param name="valueData">Contains the text, bounding box and content of the value of the field in the form.</param>
        /// <param name="value">The strongly-typed value of this field.</param>
        /// <param name="confidence">Measures the degree of certainty of the recognition result.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FormField"/> instance for mocking.</returns>
        public static FormField FormField(string name, FieldData labelData, FieldData valueData, FieldValue value, float confidence) =>
            new FormField(name, labelData, valueData, value, confidence);

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FormLine"/> class.
        /// </summary>
        /// <param name="boundingBox">The quadrilateral bounding box that outlines the text of this element.</param>
        /// <param name="pageNumber">The 1-based number of the page in which this element is present.</param>
        /// <param name="text">The text of this form element.</param>
        /// <param name="words">A list of the words that make up the line.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FormLine"/> instance for mocking.</returns>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static FormLine FormLine(FieldBoundingBox boundingBox, int pageNumber, string text, IReadOnlyList<FormWord> words) =>
            FormLine(boundingBox, pageNumber, text, words, default);

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FormLine"/> class.
        /// </summary>
        /// <param name="boundingBox">The quadrilateral bounding box that outlines the text of this element.</param>
        /// <param name="pageNumber">The 1-based number of the page in which this element is present.</param>
        /// <param name="text">The text of this form element.</param>
        /// <param name="words">A list of the words that make up the line.</param>
        /// <param name="appearance">An object representing the appearance of the text line.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FormLine"/> instance for mocking.</returns>
        public static FormLine FormLine(FieldBoundingBox boundingBox, int pageNumber, string text, IReadOnlyList<FormWord> words, TextAppearance appearance)
        {
            words = words?.ToList();

            return new FormLine(boundingBox, pageNumber, text, words, appearance);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FormPage"/> class.
        /// </summary>
        /// <param name="pageNumber">The 1-based page number in the input document.</param>
        /// <param name="width">The width of the image/PDF in pixels/inches, respectively.</param>
        /// <param name="height">The height of the image/PDF in pixels/inches, respectively.</param>
        /// <param name="textAngle">The general orientation of the text in clockwise direction, measured in degrees between (-180, 180].</param>
        /// <param name="unit">The unit used by the width, height and <see cref="FieldBoundingBox"/> properties. For images, the unit is pixel. For PDF, the unit is inch.</param>
        /// <param name="lines">A list of recognized lines of text.</param>
        /// <param name="tables">A list of recognized tables contained in this page.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FormPage"/> instance for mocking.</returns>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static FormPage FormPage(int pageNumber, float width, float height, float textAngle, LengthUnit unit, IReadOnlyList<FormLine> lines, IReadOnlyList<FormTable> tables) =>
            FormPage(pageNumber, width, height, textAngle, unit, lines, tables, default);

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FormPage"/> class.
        /// </summary>
        /// <param name="pageNumber">The 1-based page number in the input document.</param>
        /// <param name="width">The width of the image/PDF in pixels/inches, respectively.</param>
        /// <param name="height">The height of the image/PDF in pixels/inches, respectively.</param>
        /// <param name="textAngle">The general orientation of the text in clockwise direction, measured in degrees between (-180, 180].</param>
        /// <param name="unit">The unit used by the width, height and <see cref="FieldBoundingBox"/> properties. For images, the unit is pixel. For PDF, the unit is inch.</param>
        /// <param name="lines">A list of recognized lines of text.</param>
        /// <param name="tables">A list of recognized tables contained in this page.</param>
        /// <param name="selectionMarks">A list of recognized selection marks contained in this page.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FormPage"/> instance for mocking.</returns>
        public static FormPage FormPage(int pageNumber, float width, float height, float textAngle, LengthUnit unit, IReadOnlyList<FormLine> lines, IReadOnlyList<FormTable> tables, IReadOnlyList<FormSelectionMark> selectionMarks)
        {
            lines = lines?.ToList();
            tables = tables?.ToList();
            selectionMarks = selectionMarks?.ToList();

            return new FormPage(pageNumber, width, height, textAngle, unit, lines, tables, selectionMarks);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FormPageCollection"/> class.
        /// This class is a read-only wrapper around the specified list.
        /// </summary>
        /// <param name="list">The list to wrap.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FormPageCollection"/> instance for mocking.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="list"/> is null.</exception>
        public static FormPageCollection FormPageCollection(IList<FormPage> list) =>
            new FormPageCollection(list);

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FormPageRange"/> structure.
        /// </summary>
        /// <param name="firstPageNumber">The first page number of the range.</param>
        /// <param name="lastPageNumber">The last page number of the range.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FormPageRange"/> instance for mocking.</returns>
        public static FormPageRange FormPageRange(int firstPageNumber, int lastPageNumber) =>
            new FormPageRange(firstPageNumber, lastPageNumber);

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FormRecognizerError"/> class.
        /// </summary>
        /// <param name="errorCode">The error code.</param>
        /// <param name="message">The error message.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FormRecognizerError"/> instance for mocking.</returns>
        public static FormRecognizerError FormRecognizerError(string errorCode, string message) =>
            new FormRecognizerError(errorCode, message);

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FormSelectionMark"/> class.
        /// </summary>
        /// <param name="boundingBox">The quadrilateral bounding box that outlines the element.</param>
        /// <param name="pageNumber">The 1-based number of the page in which this element is present.</param>
        /// <param name="text">The text of selection mark value.</param>
        /// <param name="confidence">Measures the degree of certainty of the recognition result.</param>
        /// <param name="state">Selection mark state value.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FormSelectionMark"/> instance for mocking.</returns>
        public static FormSelectionMark FormSelectionMark(FieldBoundingBox boundingBox, int pageNumber, string text, float confidence, SelectionMarkState state) =>
            new FormSelectionMark(boundingBox, pageNumber, text, confidence, state);

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FormTable"/> class.
        /// </summary>
        /// <param name="pageNumber">The 1-based number of the page in which this table is present.</param>
        /// <param name="columnCount">The number of columns in this table.</param>
        /// <param name="rowCount">The number of rows in this table.</param>
        /// <param name="cells">A list of cells contained in this table.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FormTable"/> instance for mocking.</returns>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static FormTable FormTable(int pageNumber, int columnCount, int rowCount, IReadOnlyList<FormTableCell> cells) =>
            FormTable(pageNumber, columnCount, rowCount, cells, default);

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FormTable"/> class.
        /// </summary>
        /// <param name="pageNumber">The 1-based number of the page in which this table is present.</param>
        /// <param name="columnCount">The number of columns in this table.</param>
        /// <param name="rowCount">The number of rows in this table.</param>
        /// <param name="cells">A list of cells contained in this table.</param>
        /// <param name="boundingBox">The quadrilateral bounding box that outlines the table.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FormTable"/> instance for mocking.</returns>
        public static FormTable FormTable(int pageNumber, int columnCount, int rowCount, IReadOnlyList<FormTableCell> cells, FieldBoundingBox boundingBox)
        {
            cells = cells?.ToList();

            return new FormTable(pageNumber, columnCount, rowCount, cells, boundingBox);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FormTableCell"/> class.
        /// </summary>
        /// <param name="boundingBox">The quadrilateral bounding box that outlines the text of this element.</param>
        /// <param name="pageNumber">The 1-based number of the page in which this element is present.</param>
        /// <param name="text">The text of this form element.</param>
        /// <param name="columnIndex">The column index of the cell.</param>
        /// <param name="rowIndex">The row index of the cell.</param>
        /// <param name="columnSpan">The number of columns spanned by this cell.</param>
        /// <param name="rowSpan">The number of rows spanned by this cell.</param>
        /// <param name="isHeader"><c>true</c> if this cell is a header cell. Otherwise, <c>false</c>.</param>
        /// <param name="isFooter"><c>true</c> if this cell is a footer cell. Otherwise, <c>false</c>.</param>
        /// <param name="confidence">Measures the degree of certainty of the recognition result.</param>
        /// <param name="fieldElements">A list of references to the field elements constituting this cell.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FormTableCell"/> instance for mocking.</returns>
        public static FormTableCell FormTableCell(FieldBoundingBox boundingBox, int pageNumber, string text, int columnIndex, int rowIndex, int columnSpan, int rowSpan, bool isHeader, bool isFooter, float confidence, IReadOnlyList<FormElement> fieldElements)
        {
            fieldElements = fieldElements?.ToList();

            return new FormTableCell(boundingBox, pageNumber, text, columnIndex, rowIndex, columnSpan, rowSpan, isHeader, isFooter, confidence, fieldElements);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.FormWord"/> class.
        /// </summary>
        /// <param name="boundingBox">The quadrilateral bounding box that outlines the text of this element.</param>
        /// <param name="pageNumber">The 1-based number of the page in which this element is present.</param>
        /// <param name="text">The text of this form element.</param>
        /// <param name="confidence">Measures the degree of certainty of the recognition result.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.FormWord"/> instance for mocking.</returns>
        public static FormWord FormWord(FieldBoundingBox boundingBox, int pageNumber, string text, float confidence) =>
            new FormWord(boundingBox, pageNumber, text, confidence);

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.RecognizedForm"/> class.
        /// </summary>
        /// <param name="formType">The type of form the model identified the submitted form to be.</param>
        /// <param name="pageRange">The range of pages this form spans.</param>
        /// <param name="fields">A dictionary of the fields recognized from the input document.</param>
        /// <param name="pages">A list of pages describing the recognized form elements present in the input document.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.RecognizedForm"/> instance for mocking.</returns>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static RecognizedForm RecognizedForm(string formType, FormPageRange pageRange, IReadOnlyDictionary<string, FormField> fields, IReadOnlyList<FormPage> pages) =>
            RecognizedForm(formType, pageRange, fields, pages, default, default);

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.RecognizedForm"/> class.
        /// </summary>
        /// <param name="formType">The type of form the model identified the submitted form to be.</param>
        /// <param name="pageRange">The range of pages this form spans.</param>
        /// <param name="fields">A dictionary of the fields recognized from the input document.</param>
        /// <param name="pages">A list of pages describing the recognized form elements present in the input document.</param>
        /// <param name="modelId">Model identifier of model used to analyze form if not using a prebuilt model.</param>
        /// <param name="formTypeConfidence">Confidence on the type of form the labeled model identified the submitted form to be.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.RecognizedForm"/> instance for mocking.</returns>
        public static RecognizedForm RecognizedForm(string formType, FormPageRange pageRange, IReadOnlyDictionary<string, FormField> fields, IReadOnlyList<FormPage> pages, string modelId, float? formTypeConfidence)
        {
            fields = fields?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
            pages = pages?.ToList();

            return new RecognizedForm(formType, pageRange, fields, pages, modelId, formTypeConfidence);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.RecognizedFormCollection"/> class.
        /// This class is a read-only wrapper around the specified list.
        /// </summary>
        /// <param name="list">The list to wrap.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.RecognizedFormCollection"/> instance for mocking.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="list"/> is null.</exception>
        public static RecognizedFormCollection RecognizedFormCollection(IList<RecognizedForm> list) =>
            new RecognizedFormCollection(list);

        /// <summary>
        /// Initializes a new instance of the <see cref="FormRecognizer.Models.TextAppearance"/> class.
        /// </summary>
        /// <param name="styleName">The text line style name.</param>
        /// <param name="styleConfidence">Measures the degree of certainty of the recognition result.</param>
        /// <returns>A new <see cref="FormRecognizer.Models.TextAppearance"/> instance for mocking.</returns>
        public static TextAppearance TextAppearance(TextStyleName styleName, float styleConfidence) =>
            new TextAppearance(styleName, styleConfidence);

        /// <summary>
        /// Initializes a new instance of the <see cref="Training.TrainingDocumentInfo"/> class.
        /// </summary>
        /// <param name="name">Training document name.</param>
        /// <param name="pageCount">Total number of pages trained.</param>
        /// <param name="errors">List of errors.</param>
        /// <param name="status">Status of the training operation.</param>
        /// <returns>A new <see cref="Training.TrainingDocumentInfo"/> instance for mocking.</returns>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static TrainingDocumentInfo TrainingDocumentInfo(string name, int pageCount, IEnumerable<FormRecognizerError> errors, TrainingStatus status) =>
            TrainingDocumentInfo(name, pageCount, errors?.ToList(), status, default);

        /// <summary>
        /// Initializes a new instance of the <see cref="Training.TrainingDocumentInfo"/> class.
        /// </summary>
        /// <param name="name">Training document name.</param>
        /// <param name="pageCount">Total number of pages trained.</param>
        /// <param name="errors">List of errors.</param>
        /// <param name="status">Status of the training operation.</param>
        /// <param name="modelId">The unique identifier of the model.</param>
        /// <returns>A new <see cref="Training.TrainingDocumentInfo"/> instance for mocking.</returns>
        public static TrainingDocumentInfo TrainingDocumentInfo(string name, int pageCount, IEnumerable<FormRecognizerError> errors, TrainingStatus status, string modelId)
        {
            return new TrainingDocumentInfo(name, pageCount, errors?.ToList(), status, modelId);
        }
    }
}


text:
package com.opengamma.analytics.financial.model.option.pricing.tree;

import static org.testng.Assert.assertEquals;
import static org.testng.AssertJUnit.assertTrue;

import org.testng.annotations.Test;

import com.opengamma.analytics.financial.greeks.Greek;
import com.opengamma.analytics.financial.greeks.GreekResultCollection;
import com.opengamma.analytics.math.statistics.distribution.NormalDistribution;
import com.opengamma.analytics.math.statistics.distribution.ProbabilityDistribution;
import com.opengamma.util.test.TestGroup;

/**
 * Test.
 */
@Test(groups = TestGroup.UNIT)
public class LogOptionFunctionProviderTest {

  private static final ProbabilityDistribution<Double> NORMAL = new NormalDistribution(0, 1);

  private static final BinomialTreeOptionPricingModel _model = new BinomialTreeOptionPricingModel();
  private static final TrinomialTreeOptionPricingModel _modelTrinomial = new TrinomialTreeOptionPricingModel();
  private static final double SPOT = 105.;
  private static final double[] STRIKES = new double[] {97., 105., 105.1, 114. };
  private static final double TIME = 4.2;
  private static final double[] INTERESTS = new double[] {-0.01, 0.017, 0.05 };
  private static final double[] VOLS = new double[] {0.05, 0.1, 0.5 };
  private static final double[] DIVIDENDS = new double[] {0.005, 0.014 };

  /**
   *
   */
  @Test
  public void priceLatticeTrinomialTest() {
    final LatticeSpecification[] lattices = new LatticeSpecification[] {new CoxRossRubinsteinLatticeSpecification(), new JarrowRuddLatticeSpecification(),
        new TrigeorgisLatticeSpecification(), new TianLatticeSpecification() };

    for (final LatticeSpecification lattice : lattices) {
      for (final double strike : STRIKES) {
        for (final double interest : INTERESTS) {
          for (final double vol : VOLS) {
            final int nSteps = 91;
            for (final double dividend : DIVIDENDS) {
              final OptionFunctionProvider1D function = new LogOptionFunctionProvider(strike, TIME, nSteps);
              final double exactDiv = price(SPOT, strike, TIME, vol, interest, interest - dividend);
              final double resDiv = _modelTrinomial.getPrice(lattice, function, SPOT, vol, interest, dividend);
              final double refDiv = Math.max(exactDiv, 1.) * 1.e-3;
              assertEquals(resDiv, exactDiv, refDiv);
            }
          }
        }
      }
    }
  }

  /**
   *
   */
  @Test
  public void greekTrinomialTest() {
    final LatticeSpecification[] lattices = new LatticeSpecification[] {new CoxRossRubinsteinLatticeSpecification(), new JarrowRuddLatticeSpecification(),
        new TrigeorgisLatticeSpecification(), new TianLatticeSpecification() };
    for (final LatticeSpecification lattice : lattices) {
      for (final double strike : STRIKES) {
        for (final double interest : INTERESTS) {
          for (final double vol : VOLS) {
            final int nSteps = 91;
            for (final double dividend : DIVIDENDS) {
              final OptionFunctionProvider1D function = new LogOptionFunctionProvider(strike, TIME, nSteps);
              final GreekResultCollection resDiv = _modelTrinomial.getGreeks(lattice, function, SPOT, vol, interest, dividend);
              final double priceDiv = price(SPOT, strike, TIME, vol, interest, interest - dividend);
              final double refPriceDiv = Math.max(Math.abs(priceDiv), 1.) * 1.e-3;
              assertEquals(resDiv.get(Greek.FAIR_PRICE), priceDiv, refPriceDiv);
              final double deltaDiv = delta(SPOT, strike, TIME, vol, interest, interest - dividend);
              final double refDeltaDiv = Math.max(Math.abs(deltaDiv), 1.) * 1.e-3;
              assertEquals(resDiv.get(Greek.DELTA), deltaDiv, refDeltaDiv);
              final double gammaDiv = gamma(SPOT, strike, TIME, vol, interest, interest - dividend);
              final double refGammaDiv = Math.max(Math.abs(gammaDiv), 1.) * 1.e-3;
              assertEquals(resDiv.get(Greek.GAMMA), gammaDiv, refGammaDiv);
              final double thetaDiv = theta(SPOT, strike, TIME, vol, interest, interest - dividend);
              final double refThetaDiv = Math.max(Math.abs(thetaDiv), 1.) * 1.e-3;
              assertEquals(resDiv.get(Greek.THETA), thetaDiv, refThetaDiv);
            }
          }
        }
      }
    }
  }

  /**
   *
   */
  @Test
  public void priceLatticeTest() {
    final LatticeSpecification[] lattices = new LatticeSpecification[] {new CoxRossRubinsteinLatticeSpecification(), new JarrowRuddLatticeSpecification(), new TrigeorgisLatticeSpecification(),
        new JabbourKraminYoungLatticeSpecification(), new TianLatticeSpecification() };

    for (final LatticeSpecification lattice : lattices) {
      for (final double strike : STRIKES) {
        for (final double interest : INTERESTS) {
          for (final double vol : VOLS) {
            final int nSteps = 151;
            for (final double dividend : DIVIDENDS) {
              final OptionFunctionProvider1D function = new LogOptionFunctionProvider(strike, TIME, nSteps);
              final double exactDiv = price(SPOT, strike, TIME, vol, interest, interest - dividend);
              final double resDiv = _model.getPrice(lattice, function, SPOT, vol, interest, dividend);
              final double refDiv = Math.max(exactDiv, 1.) * 1.e-3;
              assertEquals(resDiv, exactDiv, refDiv);
            }
          }
        }
      }
    }
  }

  /**
   *
   */
  @Test
  public void priceeisenReimerTest() {
    final LatticeSpecification lattice = new LeisenReimerLatticeSpecification();

    for (final double strike : STRIKES) {
      for (final double interest : INTERESTS) {
        for (final double vol : VOLS) {
          final int nSteps = 919;
          for (final double dividend : DIVIDENDS) {
            final OptionFunctionProvider1D function = new LogOptionFunctionProvider(strike, TIME, nSteps);
            final double exactDiv = price(SPOT, strike, TIME, vol, interest, interest - dividend);
            final double resDiv = _model.getPrice(lattice, function, SPOT, vol, interest, dividend);
            final double refDiv = Math.max(exactDiv, 1.) * 1.e-4;
            assertEquals(resDiv, exactDiv, refDiv);
          }
        }
      }
    }
  }

  /**
   * The dividend is cash or proportional to asset price
   */
  @Test
  public void priceDiscreteDividendTest() {
    final LatticeSpecification[] lattices = new LatticeSpecification[] {new CoxRossRubinsteinLatticeSpecification(), new JarrowRuddLatticeSpecification(), new TrigeorgisLatticeSpecification(),
        new JabbourKraminYoungLatticeSpecification(), new TianLatticeSpecification(), new LeisenReimerLatticeSpecification() };

    final double[] propDividends = new double[] {0.01, 0.01, 0.01 };
    final double[] cashDividends = new double[] {5., 10., 8. };
    final double[] dividendTimes = new double[] {TIME / 6., TIME / 3., TIME / 2. };

    for (final LatticeSpecification lattice : lattices) {
      for (final double strike : STRIKES) {
        for (final double interest : INTERESTS) {
          for (final double vol : VOLS) {
            final int nSteps = 163;
            final OptionFunctionProvider1D function = new LogOptionFunctionProvider(strike, TIME, nSteps);
            final DividendFunctionProvider cashDividend = new CashDividendFunctionProvider(dividendTimes, cashDividends);
            final DividendFunctionProvider propDividend = new ProportionalDividendFunctionProvider(dividendTimes, propDividends);
            final double resSpot = SPOT * (1. - propDividends[0]) * (1. - propDividends[1]) * (1. - propDividends[2]);
            final double modSpot = SPOT - cashDividends[0] * Math.exp(-interest * dividendTimes[0]) - cashDividends[1] * Math.exp(-interest * dividendTimes[1]) - cashDividends[2] *
                Math.exp(-interest * dividendTimes[2]);
            final double exactProp = price(resSpot, strike, TIME, vol, interest, interest);
            final double appCash = price(modSpot, strike, TIME, vol, interest, interest);
            final double resProp = _model.getPrice(lattice, function, SPOT, vol, interest, propDividend);
            final double refProp = Math.max(exactProp, 1.) * 1.e-3;
            assertEquals(resProp, exactProp, refProp);
            final double resCash = _model.getPrice(lattice, function, SPOT, vol, interest, cashDividend);
            final double refCash = Math.max(appCash, 1.) * 1.e-3;
            assertEquals(resCash, appCash, refCash);

            if (lattice instanceof CoxRossRubinsteinLatticeSpecification || lattice instanceof JarrowRuddLatticeSpecification || lattice instanceof TrigeorgisLatticeSpecification ||
                lattice instanceof TianLatticeSpecification) {
              final int nStepsTri = 81;
              final OptionFunctionProvider1D functionTri = new LogOptionFunctionProvider(strike, TIME, nStepsTri);
              final double resPropTrinomial = _modelTrinomial.getPrice(lattice, functionTri, SPOT, vol, interest, propDividend);
              final double resCashTrinomial = _modelTrinomial.getPrice(lattice, functionTri, SPOT, vol, interest, cashDividend);
              assertEquals(resPropTrinomial, exactProp, Math.max(exactProp, 1.) * 1.e-3);
              assertEquals(resCashTrinomial, appCash, Math.max(appCash, 1.) * 1.e-3);
            }
          }
        }
      }
    }
  }

  /**
   *
   */
  @Test
  public void greekTest() {
    final LatticeSpecification[] lattices = new LatticeSpecification[] {new CoxRossRubinsteinLatticeSpecification(), new JarrowRuddLatticeSpecification(),
        new TrigeorgisLatticeSpecification(), new JabbourKraminYoungLatticeSpecification(), new TianLatticeSpecification() };
    for (final LatticeSpecification lattice : lattices) {
      for (final double strike : STRIKES) {
        for (final double interest : INTERESTS) {
          for (final double vol : VOLS) {
            final int nSteps = 163; //Slow convergence
            for (final double dividend : DIVIDENDS) {
              final OptionFunctionProvider1D function = new LogOptionFunctionProvider(strike, TIME, nSteps);
              final GreekResultCollection resDiv = _model.getGreeks(lattice, function, SPOT, vol, interest, dividend);
              final double priceDiv = price(SPOT, strike, TIME, vol, interest, interest - dividend);
              final double refPriceDiv = Math.max(Math.abs(priceDiv), 1.) * 1.e-3;
              assertEquals(resDiv.get(Greek.FAIR_PRICE), priceDiv, refPriceDiv);
              final double deltaDiv = delta(SPOT, strike, TIME, vol, interest, interest - dividend);
              final double refDeltaDiv = Math.max(Math.abs(deltaDiv), 1.) * 1.e-2;
              assertEquals(resDiv.get(Greek.DELTA), deltaDiv, refDeltaDiv);
              final double gammaDiv = gamma(SPOT, strike, TIME, vol, interest, interest - dividend);
              final double refGammaDiv = Math.max(Math.abs(gammaDiv), 1.) * 1.e-2;
              assertEquals(resDiv.get(Greek.GAMMA), gammaDiv, refGammaDiv);
              final double thetaDiv = theta(SPOT, strike, TIME, vol, interest, interest - dividend);
              final double refThetaDiv = Math.max(Math.abs(thetaDiv), 1.) * 1.e-2;
              assertEquals(resDiv.get(Greek.THETA), thetaDiv, refThetaDiv);
            }
          }
        }
      }
    }
  }

  /**
   *
   */
  @Test
  public void greekLeisenReimerTest() {
    final LatticeSpecification lattice = new LeisenReimerLatticeSpecification();

    for (final double strike : STRIKES) {
      for (final double interest : INTERESTS) {
        for (final double vol : VOLS) {
          final int nSteps = 919;
          for (final double dividend : DIVIDENDS) {
            final OptionFunctionProvider1D function = new LogOptionFunctionProvider(strike, TIME, nSteps);
            final GreekResultCollection resDiv = _model.getGreeks(lattice, function, SPOT, vol, interest, dividend);
            final double priceDiv = price(SPOT, strike, TIME, vol, interest, interest - dividend);
            final double refPriceDiv = Math.max(Math.abs(priceDiv), 1.) * 1.e-4;
            assertEquals(resDiv.get(Greek.FAIR_PRICE), priceDiv, refPriceDiv);
            final double deltaDiv = delta(SPOT, strike, TIME, vol, interest, interest - dividend);
            final double refDeltaDiv = Math.max(Math.abs(deltaDiv), 1.) * 1.e-3;
            assertEquals(resDiv.get(Greek.DELTA), deltaDiv, refDeltaDiv);
            final double gammaDiv = gamma(SPOT, strike, TIME, vol, interest, interest - dividend);
            final double refGammaDiv = Math.max(Math.abs(gammaDiv), 1.) * 1.e-3;
            assertEquals(resDiv.get(Greek.GAMMA), gammaDiv, refGammaDiv);
            final double thetaDiv = theta(SPOT, strike, TIME, vol, interest, interest - dividend);
            final double refThetaDiv = Math.max(Math.abs(thetaDiv), 1.) * 1.e-3;
            assertEquals(resDiv.get(Greek.THETA), thetaDiv, refThetaDiv);
          }
        }
      }
    }
  }

  /**
   * The dividend is cash or proportional to asset price
   */
  @Test
  public void greeksDiscreteDividendLatticeTest() {
    final LatticeSpecification[] lattices = new LatticeSpecification[] {new CoxRossRubinsteinLatticeSpecification(), new JarrowRuddLatticeSpecification(), new TrigeorgisLatticeSpecification(),
        new JabbourKraminYoungLatticeSpecification(), new TianLatticeSpecification(), new LeisenReimerLatticeSpecification() };

    final double[] propDividends = new double[] {0.01, 0.03, 0.02 };
    final double[] cashDividends = new double[] {5., 10., 8. };
    final double[] dividendTimes = new double[] {TIME / 6., TIME / 3., TIME / 2. };

    for (final LatticeSpecification lattice : lattices) {
      for (final double strike : STRIKES) {
        for (final double interest : INTERESTS) {
          for (final double vol : VOLS) {
            final int nSteps = 163;
            final double resSpot = SPOT * (1. - propDividends[0]) * (1. - propDividends[1]) * (1. - propDividends[2]);
            final double modSpot = SPOT - cashDividends[0] * Math.exp(-interest * dividendTimes[0]) - cashDividends[1] * Math.exp(-interest * dividendTimes[1]) - cashDividends[2] *
                Math.exp(-interest * dividendTimes[2]);
            final double exactPriceProp = price(resSpot, strike, TIME, vol, interest, interest);
            final double exactDeltaProp = delta(resSpot, strike, TIME, vol, interest, interest);
            final double exactGammaProp = gamma(resSpot, strike, TIME, vol, interest, interest);
            final double exactThetaProp = theta(resSpot, strike, TIME, vol, interest, interest);

            final double appPriceCash = price(modSpot, strike, TIME, vol, interest, interest);
            final double appDeltaCash = delta(modSpot, strike, TIME, vol, interest, interest);
            final double appGammaCash = gamma(modSpot, strike, TIME, vol, interest, interest);
            final double appThetaCash = theta(modSpot, strike, TIME, vol, interest, interest);

            final OptionFunctionProvider1D function = new LogOptionFunctionProvider(strike, TIME, nSteps);
            final DividendFunctionProvider cashDividend = new CashDividendFunctionProvider(dividendTimes, cashDividends);
            final DividendFunctionProvider propDividend = new ProportionalDividendFunctionProvider(dividendTimes, propDividends);
            final GreekResultCollection resProp = _model.getGreeks(lattice, function, SPOT, vol, interest, propDividend);
            final GreekResultCollection resCash = _model.getGreeks(lattice, function, SPOT, vol, interest, cashDividend);

            assertEquals(resProp.get(Greek.FAIR_PRICE), exactPriceProp, Math.max(1., Math.abs(exactPriceProp)) * 1.e-3);
            assertEquals(resProp.get(Greek.DELTA), exactDeltaProp, Math.max(1., Math.abs(exactDeltaProp)) * 1.e-2);
            assertEquals(resProp.get(Greek.GAMMA), exactGammaProp, Math.max(1., Math.abs(exactGammaProp)) * 1.e-2);
            assertEquals(resProp.get(Greek.THETA), exactThetaProp, Math.max(1., Math.abs(exactThetaProp)) * 1.e-2);

            assertEquals(resCash.get(Greek.FAIR_PRICE), appPriceCash, Math.max(1., Math.abs(appPriceCash)) * 1.e-3);
            assertEquals(resCash.get(Greek.DELTA), appDeltaCash, Math.max(1., Math.abs(appDeltaCash)) * 1.e-2);
            assertEquals(resCash.get(Greek.GAMMA), appGammaCash, Math.max(1., Math.abs(appGammaCash)) * 1.e-2);
            assertEquals(resCash.get(Greek.THETA), appThetaCash, Math.max(1., Math.abs(appThetaCash)) * 1.e-2);

            if (lattice instanceof CoxRossRubinsteinLatticeSpecification || lattice instanceof JarrowRuddLatticeSpecification || lattice instanceof TrigeorgisLatticeSpecification ||
                lattice instanceof TianLatticeSpecification) {
              final int nStepsTri = 85;
              final OptionFunctionProvider1D functionTri = new LogOptionFunctionProvider(strike, TIME, nStepsTri);
              final GreekResultCollection resPropTrinomial = _modelTrinomial.getGreeks(lattice, functionTri, SPOT, vol, interest, propDividend);
              final GreekResultCollection resCashTrinomial = _modelTrinomial.getGreeks(lattice, functionTri, SPOT, vol, interest, cashDividend);

              assertEquals(resPropTrinomial.get(Greek.FAIR_PRICE), exactPriceProp, Math.max(1., Math.abs(exactPriceProp)) * 1.e-3);
              assertEquals(resPropTrinomial.get(Greek.DELTA), exactDeltaProp, Math.max(1., Math.abs(exactDeltaProp)) * 1.e-2);
              assertEquals(resPropTrinomial.get(Greek.GAMMA), exactGammaProp, Math.max(1., Math.abs(exactGammaProp)) * 1.e-2);
              assertEquals(resPropTrinomial.get(Greek.THETA), exactThetaProp, Math.max(1., Math.abs(exactThetaProp)) * 1.e-2);

              assertEquals(resCashTrinomial.get(Greek.FAIR_PRICE), appPriceCash, Math.max(1., Math.abs(appPriceCash)) * 1.e-3);
              assertEquals(resCashTrinomial.get(Greek.DELTA), appDeltaCash, Math.max(1., Math.abs(appDeltaCash)) * 1.e-2);
              assertEquals(resCashTrinomial.get(Greek.GAMMA), appGammaCash, Math.max(1., Math.abs(appGammaCash)) * 1.e-2);
              assertEquals(resCashTrinomial.get(Greek.THETA), appThetaCash, Math.max(1., Math.abs(appThetaCash)) * 1.e-2);
            }
          }
        }
      }
    }
  }

  /**
   * non-constant volatility and interest rate
   */
  @Test
  public void timeVaryingVolTest() {
    final LatticeSpecification lattice1 = new TimeVaryingLatticeSpecification();
    final double[] time_set = new double[] {0.5, 1.2 };
    final int steps = 973;

    final double[] vol = new double[steps];
    final double[] rate = new double[steps];
    final double[] dividend = new double[steps];
    final int stepsTri = 61;
    final double[] volTri = new double[stepsTri];
    final double[] rateTri = new double[stepsTri];
    final double[] dividendTri = new double[stepsTri];
    final double constA = 0.01;
    final double constB = 0.001;
    final double constC = 0.1;
    final double constD = 0.05;

    for (final double strike : STRIKES) {
      for (final double time : time_set) {
        for (int i = 0; i < steps; ++i) {
          rate[i] = constA + constB * i * time / steps;
          vol[i] = constC + constD * Math.sin(i * time / steps);
          dividend[i] = 0.005;
        }
        for (int i = 0; i < stepsTri; ++i) {
          rateTri[i] = constA + constB * i * time / steps;
          volTri[i] = constC + constD * Math.sin(i * time / steps);
          dividendTri[i] = 0.005;
        }
        final double rateRef = constA + 0.5 * constB * time;
        final double volRef = Math.sqrt(constC * constC + 0.5 * constD * constD + 2. * constC * constD / time * (1. - Math.cos(time)) - constD * constD * 0.25 / time * Math.sin(2. * time));

        final OptionFunctionProvider1D function = new LogOptionFunctionProvider(strike, time, steps);
        final double resPrice = _model.getPrice(function, SPOT, vol, rate, dividend);
        final GreekResultCollection resGreeks = _model.getGreeks(function, SPOT, vol, rate, dividend);

        final double resPriceConst = _model.getPrice(lattice1, function, SPOT, volRef, rateRef, dividend[0]);
        final GreekResultCollection resGreeksConst = _model.getGreeks(lattice1, function, SPOT, volRef, rateRef, dividend[0]);
        assertEquals(resPrice, resPriceConst, Math.max(Math.abs(resPriceConst), 1.) * 1.e-3);
        assertEquals(resGreeks.get(Greek.FAIR_PRICE), resGreeksConst.get(Greek.FAIR_PRICE), Math.max(Math.abs(resGreeksConst.get(Greek.FAIR_PRICE)), 1.) * 1.e-3);
        assertEquals(resGreeks.get(Greek.DELTA), resGreeksConst.get(Greek.DELTA), Math.max(Math.abs(resGreeksConst.get(Greek.DELTA)), 1.) * 1.e-3);
        assertEquals(resGreeks.get(Greek.GAMMA), resGreeksConst.get(Greek.GAMMA), Math.max(Math.abs(resGreeksConst.get(Greek.GAMMA)), 1.) * 1.e-3);
        assertEquals(resGreeks.get(Greek.THETA), resGreeksConst.get(Greek.THETA), Math.max(Math.abs(resGreeksConst.get(Greek.THETA)), 1.) * 1.e-1);

        final OptionFunctionProvider1D functionTri = new LogOptionFunctionProvider(strike, time, stepsTri);
        final double resPriceTrinomial = _modelTrinomial.getPrice(functionTri, SPOT, volTri, rateTri, dividendTri);
        assertEquals(resPriceTrinomial, resPriceConst, Math.max(Math.abs(resPriceConst), 1.) * 1.e-2);
        final GreekResultCollection resGreeksTrinomial = _modelTrinomial.getGreeks(functionTri, SPOT, volTri, rateTri, dividendTri);
        assertEquals(resGreeksTrinomial.get(Greek.FAIR_PRICE), resGreeksConst.get(Greek.FAIR_PRICE), Math.max(Math.abs(resGreeksConst.get(Greek.FAIR_PRICE)), 1.) * 1.e-2);
        assertEquals(resGreeksTrinomial.get(Greek.DELTA), resGreeksConst.get(Greek.DELTA), Math.max(Math.abs(resGreeksConst.get(Greek.DELTA)), 1.) * 1.e-2);
        assertEquals(resGreeksTrinomial.get(Greek.GAMMA), resGreeksConst.get(Greek.GAMMA), Math.max(Math.abs(resGreeksConst.get(Greek.GAMMA)), 1.) * 1.e-2);
        assertEquals(resGreeksTrinomial.get(Greek.THETA), resGreeksConst.get(Greek.THETA), Math.max(Math.abs(resGreeksConst.get(Greek.THETA)), 1.) * 1.e-1);
      }
    }
  }

  /**
   *
   */
  @Test(expectedExceptions = IllegalArgumentException.class)
  public void getSignErrorTest() {
    final double strike = 100.;
    final int steps = 801;
    final OptionFunctionProvider1D function = new LogOptionFunctionProvider(strike, 1., steps);
    function.getSign();
  }

  /**
   *
   */
  @Test
  public void hashCodeEqualsTest() {
    final OptionFunctionProvider1D ref = new LogOptionFunctionProvider(100., 1., 1003);
    final OptionFunctionProvider1D[] function = new OptionFunctionProvider1D[] {ref, new LogOptionFunctionProvider(100., 1., 1003), new EuropeanVanillaOptionFunctionProvider(100., 1., 1003, true),
        null };
    final int len = function.length;
    for (int i = 0; i < len; ++i) {
      if (ref.equals(function[i])) {
        assertTrue(ref.hashCode() == function[i].hashCode());
      }
    }
    for (int i = 0; i < len - 1; ++i) {
      assertTrue(function[i].equals(ref) == ref.equals(function[i]));
    }
  }

  private double price(final double spot, final double strike, final double time, final double vol, final double interest, final double cost) {
    final double d2 = (Math.log(spot / strike) + (cost - 0.5 * vol * vol) * time) / vol / Math.sqrt(time);
    final double firstTerm = Math.exp(-interest * time) * NORMAL.getPDF(d2) * vol * Math.sqrt(time);
    final double secondTerm = Math.exp(-interest * time) * (Math.log(spot / strike) + (cost - 0.5 * vol * vol) * time) * NORMAL.getCDF(d2);
    return firstTerm + secondTerm;
  }

  private double delta(final double spot, final double strike, final double time, final double vol, final double interest, final double cost) {
    final double d2 = (Math.log(spot / strike) + (cost - 0.5 * vol * vol) * time) / vol / Math.sqrt(time);
    return Math.exp(-interest * time) * NORMAL.getCDF(d2) / spot;
  }

  private double gamma(final double spot, final double strike, final double time, final double vol, final double interest, final double cost) {
    final double d2 = (Math.log(spot / strike) + (cost - 0.5 * vol * vol) * time) / vol / Math.sqrt(time);
    return Math.exp(-interest * time) * (-NORMAL.getCDF(d2) + NORMAL.getPDF(d2) / vol / Math.sqrt(time)) / spot / spot;
  }

  private double theta(final double spot, final double strike, final double time, final double vol, final double interest, final double cost) {
    final double d2 = (Math.log(spot / strike) + (cost - 0.5 * vol * vol) * time) / vol / Math.sqrt(time);
    final double d2Diff = 0.5 * (-Math.log(spot / strike) / vol / Math.pow(time, 1.5) + (cost - 0.5 * vol * vol) / vol / Math.sqrt(time));
    final double firstTerm = -interest * price(spot, strike, time, vol, interest, cost);
    final double secondTerm = Math.exp(-interest * time) *
        (-NORMAL.getPDF(d2) * d2 * d2Diff * vol * Math.sqrt(time) + 0.5 * NORMAL.getPDF(d2) * vol / Math.sqrt(time) + (cost - 0.5 * vol * vol) * NORMAL.getCDF(d2));
    final double thirdTerm = Math.exp(-interest * time) * (Math.log(spot / strike) + (cost - 0.5 * vol * vol) * time) * NORMAL.getPDF(d2) * d2Diff;
    return -firstTerm - secondTerm - thirdTerm;
  }

  /**
   * test for analytic formula
   */
  @Test(enabled = false)
  public void functionTest() {
    final double eps = 1.e-6;
    for (final double strike : STRIKES) {
      for (final double interest : INTERESTS) {
        for (final double vol : VOLS) {
          for (final double dividend : DIVIDENDS) {
            final double delta = delta(SPOT, strike, TIME, vol, interest, interest - dividend);
            final double gamma = gamma(SPOT, strike, TIME, vol, interest, interest - dividend);
            final double theta = theta(SPOT, strike, TIME, vol, interest, interest - dividend);
            final double upSpot = price(SPOT + eps, strike, TIME, vol, interest, interest - dividend);
            final double downSpot = price(SPOT - eps, strike, TIME, vol, interest, interest - dividend);
            final double upSpotDelta = delta(SPOT + eps, strike, TIME, vol, interest, interest - dividend);
            final double downSpotDelta = delta(SPOT - eps, strike, TIME, vol, interest, interest - dividend);
            final double upTime = price(SPOT, strike, TIME + eps, vol, interest, interest - dividend);
            final double downTime = price(SPOT, strike, TIME - eps, vol, interest, interest - dividend);
            assertEquals(delta, 0.5 * (upSpot - downSpot) / eps, eps);
            assertEquals(gamma, 0.5 * (upSpotDelta - downSpotDelta) / eps, eps);
            assertEquals(theta, -0.5 * (upTime - downTime) / eps, eps);
          }
        }
      }
    }
  }
}


text:
.class public abstract Landroid/app/backup/IFullBackupRestoreObserver$Stub;
.super Landroid/os/Binder;
.source "IFullBackupRestoreObserver.java"

# interfaces
.implements Landroid/app/backup/IFullBackupRestoreObserver;

# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
    value = Landroid/app/backup/IFullBackupRestoreObserver;
.end annotation

.annotation system Ldalvik/annotation/InnerClass;
    accessFlags = 0x409
    name = "Stub"
.end annotation

.annotation system Ldalvik/annotation/MemberClasses;
    value = {
        Landroid/app/backup/IFullBackupRestoreObserver$Stub$Proxy;
    }
.end annotation

# static fields
.field private static final DESCRIPTOR:Ljava/lang/String; = "android.app.backup.IFullBackupRestoreObserver"

.field static final TRANSACTION_onBackupPackage:I = 0x2

.field static final TRANSACTION_onEndBackup:I = 0x3

.field static final TRANSACTION_onEndRestore:I = 0x6

.field static final TRANSACTION_onRestorePackage:I = 0x5

.field static final TRANSACTION_onStartBackup:I = 0x1

.field static final TRANSACTION_onStartRestore:I = 0x4

.field static final TRANSACTION_onTimeout:I = 0x7

# direct methods
.method public constructor <init>()V
    .locals 1

    .prologue
    .line 20
    invoke-direct {p0}, Landroid/os/Binder;-><init>()V

    .line 21
    const-string v0, "android.app.backup.IFullBackupRestoreObserver"

    invoke-virtual {p0, p0, v0}, Landroid/os/Binder;->attachInterface(Landroid/os/IInterface;Ljava/lang/String;)V

    .line 22
    return-void
.end method

.method public static asInterface(Landroid/os/IBinder;)Landroid/app/backup/IFullBackupRestoreObserver;
    .locals 2
    .parameter "obj"

    .prologue
    .line 29
    if-nez p0, :cond_0

    .line 30
    const/4 v0, 0x0

    .line 36
    :goto_0
    return-object v0

    .line 32
    :cond_0
    const-string v1, "android.app.backup.IFullBackupRestoreObserver"

    invoke-interface {p0, v1}, Landroid/os/IBinder;->queryLocalInterface(Ljava/lang/String;)Landroid/os/IInterface;

    move-result-object v0

    .line 33
    .local v0, iin:Landroid/os/IInterface;
    if-eqz v0, :cond_1

    instance-of v1, v0, Landroid/app/backup/IFullBackupRestoreObserver;

    if-eqz v1, :cond_1

    .line 34
    check-cast v0, Landroid/app/backup/IFullBackupRestoreObserver;

    goto :goto_0

    .line 36
    :cond_1
    new-instance v0, Landroid/app/backup/IFullBackupRestoreObserver$Stub$Proxy;

    .end local v0           #iin:Landroid/os/IInterface;
    invoke-direct {v0, p0}, Landroid/app/backup/IFullBackupRestoreObserver$Stub$Proxy;-><init>(Landroid/os/IBinder;)V

    goto :goto_0
.end method

# virtual methods
.method public asBinder()Landroid/os/IBinder;
    .locals 0

    .prologue
    .line 40
    return-object p0
.end method

.method public onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
    .locals 3
    .parameter "code"
    .parameter "data"
    .parameter "reply"
    .parameter "flags"
    .annotation system Ldalvik/annotation/Throws;
        value = {
            Landroid/os/RemoteException;
        }
    .end annotation

    .prologue
    const/4 v1, 0x1

    .line 44
    sparse-switch p1, :sswitch_data_0

    .line 98
    invoke-super {p0, p1, p2, p3, p4}, Landroid/os/Binder;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z

    move-result v1

    :goto_0
    return v1

    .line 48
    :sswitch_0
    const-string v2, "android.app.backup.IFullBackupRestoreObserver"

    invoke-virtual {p3, v2}, Landroid/os/Parcel;->writeString(Ljava/lang/String;)V

    goto :goto_0

    .line 53
    :sswitch_1
    const-string v2, "android.app.backup.IFullBackupRestoreObserver"

    invoke-virtual {p2, v2}, Landroid/os/Parcel;->enforceInterface(Ljava/lang/String;)V

    .line 54
    invoke-virtual {p0}, Landroid/app/backup/IFullBackupRestoreObserver$Stub;->onStartBackup()V

    goto :goto_0

    .line 59
    :sswitch_2
    const-string v2, "android.app.backup.IFullBackupRestoreObserver"

    invoke-virtual {p2, v2}, Landroid/os/Parcel;->enforceInterface(Ljava/lang/String;)V

    .line 61
    invoke-virtual {p2}, Landroid/os/Parcel;->readString()Ljava/lang/String;

    move-result-object v0

    .line 62
    .local v0, _arg0:Ljava/lang/String;
    invoke-virtual {p0, v0}, Landroid/app/backup/IFullBackupRestoreObserver$Stub;->onBackupPackage(Ljava/lang/String;)V

    goto :goto_0

    .line 67
    .end local v0           #_arg0:Ljava/lang/String;
    :sswitch_3
    const-string v2, "android.app.backup.IFullBackupRestoreObserver"

    invoke-virtual {p2, v2}, Landroid/os/Parcel;->enforceInterface(Ljava/lang/String;)V

    .line 68
    invoke-virtual {p0}, Landroid/app/backup/IFullBackupRestoreObserver$Stub;->onEndBackup()V

    goto :goto_0

    .line 73
    :sswitch_4
    const-string v2, "android.app.backup.IFullBackupRestoreObserver"

    invoke-virtual {p2, v2}, Landroid/os/Parcel;->enforceInterface(Ljava/lang/String;)V

    .line 74
    invoke-virtual {p0}, Landroid/app/backup/IFullBackupRestoreObserver$Stub;->onStartRestore()V

    goto :goto_0

    .line 79
    :sswitch_5
    const-string v2, "android.app.backup.IFullBackupRestoreObserver"

    invoke-virtual {p2, v2}, Landroid/os/Parcel;->enforceInterface(Ljava/lang/String;)V

    .line 81
    invoke-virtual {p2}, Landroid/os/Parcel;->readString()Ljava/lang/String;

    move-result-object v0

    .line 82
    .restart local v0       #_arg0:Ljava/lang/String;
    invoke-virtual {p0, v0}, Landroid/app/backup/IFullBackupRestoreObserver$Stub;->onRestorePackage(Ljava/lang/String;)V

    goto :goto_0

    .line 87
    .end local v0           #_arg0:Ljava/lang/String;
    :sswitch_6
    const-string v2, "android.app.backup.IFullBackupRestoreObserver"

    invoke-virtual {p2, v2}, Landroid/os/Parcel;->enforceInterface(Ljava/lang/String;)V

    .line 88
    invoke-virtual {p0}, Landroid/app/backup/IFullBackupRestoreObserver$Stub;->onEndRestore()V

    goto :goto_0

    .line 93
    :sswitch_7
    const-string v2, "android.app.backup.IFullBackupRestoreObserver"

    invoke-virtual {p2, v2}, Landroid/os/Parcel;->enforceInterface(Ljava/lang/String;)V

    .line 94
    invoke-virtual {p0}, Landroid/app/backup/IFullBackupRestoreObserver$Stub;->onTimeout()V

    goto :goto_0

    .line 44
    :sswitch_data_0
    .sparse-switch
        0x1 -> :sswitch_1
        0x2 -> :sswitch_2
        0x3 -> :sswitch_3
        0x4 -> :sswitch_4
        0x5 -> :sswitch_5
        0x6 -> :sswitch_6
        0x7 -> :sswitch_7
        0x5f4e5446 -> :sswitch_0
    .end sparse-switch
.end method