diff options
Diffstat (limited to 'vendor/github.com/StefanSchroeder/Golang-Ellipsoid/ellipsoid/ellipsoid.go')
-rwxr-xr-x | vendor/github.com/StefanSchroeder/Golang-Ellipsoid/ellipsoid/ellipsoid.go | 713 |
1 files changed, 0 insertions, 713 deletions
diff --git a/vendor/github.com/StefanSchroeder/Golang-Ellipsoid/ellipsoid/ellipsoid.go b/vendor/github.com/StefanSchroeder/Golang-Ellipsoid/ellipsoid/ellipsoid.go deleted file mode 100755 index 91874ef..0000000 --- a/vendor/github.com/StefanSchroeder/Golang-Ellipsoid/ellipsoid/ellipsoid.go +++ /dev/null @@ -1,713 +0,0 @@ -package ellipsoid - -// Written in Go by Stefan Schroeder, New York, 2013 -// Version 1.0 based on Geo::Ellipsoid Version 1.12. -// Version 1.1 Added ECEF functions. -// Version 1.2 Replaced Fabs with Abs. -// Version 1.3 Added Displacement function - -/* - -SYNOPSIS - -See hello-world.go example. - -DESCRIPTION - -ellipsoid performs geometrical calculations on the surface of -an ellipsoid. An ellipsoid is a three-dimension object formed from -the rotation of an ellipse about one of its axes. The approximate -shape of the earth is an ellipsoid, so ellipsoid can accurately -calculate distance and bearing between two widely-separated locations -on the earth's surface. - -The shape of an ellipsoid is defined by the lengths of its -semi-major and semi-minor axes. The shape may also be specifed by -the flattening ratio f as: - - f = ( semi-major - semi-minor ) / semi-major - -which, since f is a small number, is normally given as the reciprocal -of the flattening 1/f. - -The shape of the earth has been surveyed and estimated differently -at different times over the years. The two most common sets of values -used to describe the size and shape of the earth in the United States -are 'NAD27', dating from 1927, and 'WGS84', from 1984. United States -Geological Survey topographical maps, for example, use one or the -other of these values, and commonly-available Global Positioning -System (GPS) units can be set to use one or the other. -See "DEFINED ELLIPSOIDS" below for the ellipsoid survey values -that may be selected for use by ellipsoid. - -*/ - -import "math" -import "fmt" - -const ( - pi = math.Pi - twopi = math.Pi * 2.0 - maxLoopCount = 20 - eps = 1.0e-23 - debug = false - // Meter is one of the output/input units. - Meter = 0 // 1.0 meter - // Foot is one of the output/input units. - Foot = 1 // 0.3048 meter are a foot - // Kilometer is one of the output/input units. - Kilometer = 2 // 1000.0 meter are a kilometer - // Mile is one of the output/input units. - Mile = 3 // 1609.344 meter are a mile - // Nm (nautical mile) is one of the output/input units. - Nm = 4 // 1852.0 meter are a nautical mile, - // Degrees is one of the possible angle units for input/output. - Degrees = iota - // Radians is one of the possible angle units for input/output. - Radians = iota - // LongitudeIsSymmetric determines that the output longitude shall be symmetric. - LongitudeIsSymmetric = true - // LongitudeNotSymmetric determines that the output longitude shall not be symmetric. - LongitudeNotSymmetric = false - // BearingIsSymmetric determines that the output bearing shall be symmetric. - BearingIsSymmetric = true - // BearingNotSymmetric determines that the output bearing shall not be symmetric. - BearingNotSymmetric = false -) - -// Ellipsoid is the main object to store information about one ellispoid. -type Ellipsoid struct { - Ellipse ellipse - Units int - DistanceUnits int - LongitudeSymmetric bool - BearingSymmetry bool - DistanceFactor float64 - // Having the DistanceFactor AND the DistanceUnits in this struct is redundant - // but it looks nicer in the code. -} - -type ellipse struct { - Equatorial float64 - InvFlattening float64 -} - -// Location is one coordinate in LLA. -type Location struct { - Lat float64 - Lon float64 - Ele float64 -} - -func deg2rad(d float64) (r float64) { - return d * pi / 180.0 -} -func rad2deg(d float64) (r float64) { - return d * 180.0 / pi -} - -/* Init - -The Init constructor must be called with a list of parameters to set -the value of the ellipsoid to be used, the value of the units to be -used for angles and distances, and whether or not the output range -of longitudes and bearing angles should be symmetric around zero -or always greater than zero. There is no default constructor, all -arguments are required; they may not be abbreviated. - -Example: - - geo := ellipsoid.Init( - "WGS84", // for possible values see below. - ellipsoid.Degrees, // possible values: Degrees or Radians - ellipsoid.Meter, // possible values: Meter, Kilometer, - // Foot, Nm, Mile - ellipsoid.LongitudeIsSymmetric, // possible values - // LongitudeIsSymmetric or - // LongitudeNotSymmetric - ellipsoid.BearingIsSymmetric // possible - // values BearingIsSymmetric or - // BearingNotSymmetric - ) - -*/ -func Init(name string, units int, distUnits int, longSym bool, bearSym bool) (e Ellipsoid) { - m := map[string]ellipse{ - "AIRY": {6377563.396, 299.3249646}, - "AIRY-MODIFIED": {6377340.189, 299.3249646}, - "AUSTRALIAN": {6378160.0, 298.25}, - "BESSEL-1841": {6377397.155, 299.1528128}, - "BESSEL-1841-NAMIBIA": {6377483.865, 299.152813}, - "CLARKE-1866": {6378206.400, 294.978698}, - "CLARKE-1880": {6378249.145, 293.465}, - "EVEREST-1830": {6377276.345, 300.8017}, - "EVEREST-1948": {6377304.063, 300.8017}, - "EVEREST-SABAH-SARAWAK": {6377298.556, 300.801700}, - "EVEREST-1956": {6377301.243, 300.801700}, - "EVEREST-1969": {6377295.664, 300.801700}, - "FISHER-1960": {6378166.0, 298.3}, - "FISCHER-1960-MODIFIED": {6378155.000, 298.300000}, - "FISHER-1968": {6378150.0, 298.3}, - "GRS80": {6378137.0, 298.25722210088}, - "HELMERT-1906": {6378200.000, 298.300000}, - "HOUGH-1956": {6378270.0, 297.0}, - "HAYFORD": {6378388.0, 297.0}, - "IAU76": {6378140.0, 298.257}, - "INTERNATIONAL": {6378388.000, 297.000000}, - "KRASSOVSKY-1938": {6378245.0, 298.3}, - "NAD27": {6378206.4, 294.9786982138}, - "NWL-9D": {6378145.0, 298.25}, - "SGS85": {6378136.000, 298.257000}, - "SOUTHAMERICAN-1969": {6378160.0, 298.25}, - "SOVIET-1985": {6378136.0, 298.257}, - "WGS60": {6378165.000, 298.300000}, - "WGS66": {6378145.000, 298.250000}, - "WGS72": {6378135.0, 298.26}, - "WGS84": {6378137.0, 298.257223563}, - } - - e2, ok := m[name] - if !ok { - fmt.Printf("ellipsoid.go: Warning: Invalid ellipse type '%v'\n", name) - } - - // m ft km mi nm - conversion := []float64{1.0, 0.3048, 1000.0, 1609.344, 1852.0} - ellipsoid := Ellipsoid{e2, units, distUnits, longSym, bearSym, conversion[distUnits]} - return ellipsoid -} - -/* Intermediate - -Takes two coordinates with longitude and latitude; and a step count and -returns range and bearing and an array with the lons and lats of intermediate -points on a straight line (whatever that is on an ellipsoid), INCLUDING the -start and the endpoint. - -So if you put in point1 and point2 with step count 4, the output will be -(you make 4 hops, right?) - - point1 - i1 - i2 - i3 - point2 - -Each point is two float64 values, lat and lon, thus you have an array -with 4*2 + 2 = 5*2 cells. - -steps shall not be 0. - -I havent tested the upper limit for steps. - -*/ -func (ellipsoid Ellipsoid) Intermediate(lat1, lon1, lat2, lon2 float64, steps int) (distance, bearing float64, arr []float64) { - if steps == 0 { - return - } - r, phi := ellipsoid.To(lat1, lon1, lat2, lon2) - v := make([]float64, steps*2+2) - for i := 0; i <= steps; i++ { - a, b := ellipsoid.At(lat1, lon1, r*float64(i)/float64(steps), phi) - v[i*2], v[i*2+1] = a, b - } - arr = v - return r, phi, arr - -} - -/* To returns range, bearing between two specified locations. - - dist, theta = geo.To( lat1, lon1, lat2, lon2 ) - -*/ -func (ellipsoid Ellipsoid) To(lat1, lon1, lat2, lon2 float64) (distance, bearing float64) { - - if ellipsoid.Units == Degrees { - lat1 = deg2rad(lat1) - lon1 = deg2rad(lon1) - lat2 = deg2rad(lat2) - lon2 = deg2rad(lon2) - } - - distance, bearing = ellipsoid.calculateBearing(lat1, lon1, lat2, lon2) - if ellipsoid.Units == Degrees { - bearing = rad2deg(bearing) - } - - distance /= ellipsoid.DistanceFactor - - return -} - -/* At returns the list latitude,longitude in degrees or radians that is a -specified range and bearing from a given location. - - lat2, lon2 = geo.At( lat1, lon1, range, bearing ) - -*/ -func (ellipsoid Ellipsoid) At(lat1, lon1, distance, bearing float64) (lat2, lon2 float64) { - - if ellipsoid.Units == Degrees { - lat1 = deg2rad(lat1) - lon1 = deg2rad(lon1) - bearing = deg2rad(bearing) - } - - lat2, lon2 = ellipsoid.calculateTargetlocation(lat1, lon1, distance, bearing) - - if ellipsoid.LongitudeSymmetric == LongitudeIsSymmetric { - if lon2 > pi { - lon2 -= twopi - } - } - if ellipsoid.LongitudeSymmetric == LongitudeNotSymmetric { - if lon2 < 0.0 { - lon2 += twopi - } - } - - if ellipsoid.Units == Degrees { - lat2 = rad2deg(lat2) - lon2 = rad2deg(lon2) - } - - return -} - -/* Displacement returns the (x,y) displacement in distance units between the two specified -locations. - - x, y = geo.Displacement( lat1, lon1, lat2, lon2 ) - -NOTE: The x and y displacements are only approximations and only valid -between two locations that are fairly near to each other. Beyond 10 kilometers -or more, the concept of X and Y on a curved surface loses its meaning. - -*/ -func (ellipsoid Ellipsoid) Displacement(lat1, lon1, lat2, lon2 float64) (x, y float64) { - // FIXME: Normalize!!! before use. - r, bearing := ellipsoid.To(lat1, lon1, lat2, lon2) - - if ellipsoid.Units == Degrees { - bearing = deg2rad(bearing) - } - - x = r * math.Sin(bearing) - y = r * math.Cos(bearing) - return x, y -} - -/* Location returns the list (latitude,longitude) of a location at a given (x,y) -displacement from a given location. - - lat2, lon2 = geo.Location( lat1, lon1, x, y ) - -The note from Displacement applies. - -*/ -func (ellipsoid Ellipsoid) Location(lat1, lon1, x, y float64) (lat, lon float64) { - degreesPerRadian := 180.0 / math.Pi - - range1 := math.Sqrt(x*x + y*y) - bearing1 := math.Atan2(x, y) - - if ellipsoid.Units == Degrees { - bearing1 *= degreesPerRadian - } - - return ellipsoid.At(lat1, lon1, range1, bearing1) -} - -func (ellipsoid Ellipsoid) calculateTargetlocation(lat1, lon1, distance, bearing float64) (lat2, lon2 float64) { - - if debug == true { - fmt.Printf("_forward(lat1=%v,lon1=%v,range=%v,bearing=%v)\n", lat1, lon1, distance, bearing) - } - - eps := 0.5e-13 - - a := ellipsoid.Ellipse.Equatorial - f := 1.0 / ellipsoid.Ellipse.InvFlattening - r := 1.0 - f - - clat1 := math.Cos(lat1) - if clat1 == 0 { - fmt.Printf("WARNING: Division by Zero in ellipsoid.go.\n") - return 0.0, 0.0 - } - tu := r * math.Sin(lat1) / clat1 - faz := bearing - - s := ellipsoid.DistanceFactor * distance - - sf := math.Sin(faz) - cf := math.Cos(faz) - - baz := 0.0 - if cf != 0.0 { - baz = 2.0 * math.Atan2(tu, cf) - } - - cu := 1.0 / math.Sqrt(1.0+tu*tu) - su := tu * cu - sa := cu * sf - c2a := 1.0 - (sa * sa) - x := 1.0 + math.Sqrt((((1.0/(r*r))-1.0)*c2a)+1.0) - x = (x - 2.0) / x - c := 1.0 - x - c = (((x * x) / 4.0) + 1.0) / c - d := x * ((0.375 * x * x) - 1.0) - tu = ((s / r) / a) / c - y := tu - - if debug == true { - fmt.Printf("r=%.8f, tu=%.8f, faz=%.8f\n", r, tu, faz) - fmt.Printf("baz=%.8f, sf=%.8f, cf=%.8f\n", baz, sf, cf) - fmt.Printf("cu=%.8f, su=%.8f, sa=%.8f\n", cu, su, sa) - fmt.Printf("x=%.8f, c=%.8f, y=%.8f\n", x, c, y) - } - - var cy, cz, e, sy float64 - for true { - sy = math.Sin(y) - cy = math.Cos(y) - cz = math.Cos(baz + y) - e = (2.0 * cz * cz) - 1.0 - c = y - x = e * cy - y = (2.0 * e) - 1.0 - y = (((((((((sy * sy * 4.0) - 3.0) * y * cz * d) / 6.0) + x) * d) / 4.0) - cz) * sy * d) + tu - - if math.Abs(y-c) <= eps { - break - } - } - baz = (cu * cy * cf) - (su * sy) - c = r * math.Sqrt((sa*sa)+(baz*baz)) - d = su*cy + cu*sy*cf - lat2 = math.Atan2(d, c) - c = cu*cy - su*sy*cf - x = math.Atan2(sy*sf, c) - c = (((((-3.0 * c2a) + 4.0) * f) + 4.0) * c2a * f) / 16.0 - d = ((((e * cy * c) + cz) * sy * c) + y) * sa - lon2 = lon1 + x - (1.0-c)*d*f - - if debug == true { - fmt.Printf("returns(lat2=%v,lon2=%v)\n", lat2, lon2) - } - return lat2, lon2 -} - -func (ellipsoid Ellipsoid) calculateBearing(lat1, lon1, lat2, lon2 float64) (distance, bearing float64) { - a := ellipsoid.Ellipse.Equatorial - f := 1 / ellipsoid.Ellipse.InvFlattening - - if lon1 < 0 { - lon1 += twopi - } - if lon2 < 0 { - lon2 += twopi - } - - r := 1.0 - f - clat1 := math.Cos(lat1) - if clat1 == 0 { - fmt.Printf("WARNING: Division by Zero in ellipsoid.go.\n") - return 0.0, 0.0 - } - clat2 := math.Cos(lat2) - if clat2 == 0 { - fmt.Printf("WARNING: Division by Zero in ellipsoid.go.\n") - return 0.0, 0.0 - } - tu1 := r * math.Sin(lat1) / clat1 - tu2 := r * math.Sin(lat2) / clat2 - cu1 := 1.0 / (math.Sqrt((tu1 * tu1) + 1.0)) - su1 := cu1 * tu1 - cu2 := 1.0 / (math.Sqrt((tu2 * tu2) + 1.0)) - s := cu1 * cu2 - baz := s * tu2 - faz := baz * tu1 - dlon := lon2 - lon1 - - if debug == true { - fmt.Printf("a=%v, f=%v\n", a, f) - fmt.Printf("lat1=%v, lon1=%v\n", lat1, lon1) - fmt.Printf("lat2=%v, lon2=%v\n", lat2, lon2) - - fmt.Printf("r=%v, tu1=%v, tu2=%v\n", r, tu1, tu2) - fmt.Printf("faz=%.8f, dlon=%.8f, su1=%v\n", faz, dlon, su1) - } - - x := dlon - cnt := 0 - - var c2a, c, cx, cy, cz, d, del, e, sx, sy, y float64 - // This originally was a do-while loop. Exit condition is at end of loop. - for true { - if debug == true { - fmt.Printf(" x=%.8f\n", x) - } - sx = math.Sin(x) - cx = math.Cos(x) - tu1 = cu2 * sx - tu2 = baz - (su1 * cu2 * cx) - - if debug == true { - fmt.Printf(" sx=%.8f, cx=%.8f, tu1=%.8f, tu2=%.8f\n", sx, cx, tu1, tu2) - } - - sy = math.Sqrt(tu1*tu1 + tu2*tu2) - cy = s*cx + faz - y = math.Atan2(sy, cy) - var sa float64 - if sy == 0.0 { - sa = 1.0 - } else { - sa = (s * sx) / sy - } - - if debug == true { - fmt.Printf(" sy=%.8f, cy=%.8f, y=%.8f, sa=%.8f\n", sy, cy, y, sa) - } - - c2a = 1.0 - (sa * sa) - cz = faz + faz - if c2a > 0.0 { - cz = ((-cz) / c2a) + cy - } - e = (2.0 * cz * cz) - 1.0 - c = (((((-3.0 * c2a) + 4.0) * f) + 4.0) * c2a * f) / 16.0 - d = x - x = ((e*cy*c+cz)*sy*c + y) * sa - x = (1.0-c)*x*f + dlon - del = d - x - - if debug == true { - fmt.Printf(" c2a=%.8f, cz=%.8f\n", c2a, cz) - fmt.Printf(" e=%.8f, d=%.8f\n", e, d) - fmt.Printf(" (d-x)=%.8g\n", del) - } - if math.Abs(del) <= eps { - break - } - cnt++ - if cnt > maxLoopCount { - break - } - - } - - faz = math.Atan2(tu1, tu2) - baz = math.Atan2(cu1*sx, (baz*cx-su1*cu2)) + pi - x = math.Sqrt(((1.0/(r*r))-1.0)*c2a+1.0) + 1.0 - x = (x - 2.0) / x - c = 1.0 - x - c = ((x*x)/4.0 + 1.0) / c - d = ((0.375 * x * x) - 1.0) * x - x = e * cy - - if debug == true { - fmt.Printf("e=%.8f, cy=%.8f, x=%.8f\n", e, cy, x) - fmt.Printf("sy=%.8f, c=%.8f, d=%.8f\n", sy, c, d) - fmt.Printf("cz=%.8f, a=%.8f, r=%.8f\n", cz, a, r) - } - - s = 1.0 - e - e - s = ((((((((sy * sy * 4.0) - 3.0) * s * cz * d / 6.0) - x) * d / 4.0) + cz) * sy * d) + y) * c * a * r - - if debug == true { - fmt.Printf("s=%.8f\n", s) - } - - // adjust azimuth to (0,360) or (-180,180) as specified - if ellipsoid.BearingSymmetry == BearingIsSymmetric { - if faz < -(pi) { - faz += twopi - } - if faz >= pi { - faz -= twopi - } - } else { - if faz < 0 { - faz += twopi - } - if faz >= twopi { - faz -= twopi - } - } - - distance, bearing = s, faz - return -} - -/* ToLLA takes three cartesian coordinates x, y, z and returns -the latitude, longitude, elevation list. - -FIXME: This algorithm cannot handle x==0, although this is a valid value. -WARNING: I put in an if condition to catch this. Is it still necessary? - -*/ -func (ellipsoid Ellipsoid) ToLLA(x, y, z float64) (lat1, lon1, alt1 float64) { - - if x == 0 { - fmt.Printf("FATAL: Caught x==0 (div by zero).\n") - return - } - - a := ellipsoid.Ellipse.Equatorial - f := 1 / ellipsoid.Ellipse.InvFlattening - - b := a * (1.0 - f) - e := math.Sqrt((a*a - b*b) / (a * a)) - e2 := math.Sqrt((a*a - b*b) / (b * b)) // e' - esq := e * e // e squared - e2sq := e2 * e2 // e' squared - p := math.Sqrt(x*x + y*y) - - theta := math.Atan2(z*a, p*b) - stheta3 := math.Sin(theta) * math.Sin(theta) * math.Sin(theta) - ctheta3 := math.Cos(theta) * math.Cos(theta) * math.Cos(theta) - - lon1 = math.Atan2(y, x) - phi := math.Atan2(z+e2sq*b*stheta3, p-esq*a*ctheta3) - lat1 = phi - - sphisq := math.Sin(phi) * math.Sin(phi) - N := a / (math.Sqrt(1 - esq*sphisq)) - alt1 = p/math.Cos(phi) - N - - if ellipsoid.LongitudeSymmetric == LongitudeIsSymmetric { - if lon1 > pi { - lon1 -= twopi - } - } - if ellipsoid.LongitudeSymmetric == LongitudeNotSymmetric { - if lon1 < 0.0 { - lon1 += twopi - } - } - - if ellipsoid.Units == Degrees { - lat1 = rad2deg(lat1) - lon1 = rad2deg(lon1) - } - return lat1, lon1, alt1 -} - -/* ToECEF takes the latitude, longitude, elevation list and - returns three cartesian coordinates x, y, z */ -func (ellipsoid Ellipsoid) ToECEF(lat1, lon1, alt1 float64) (x, y, z float64) { - a := ellipsoid.Ellipse.Equatorial - f := 1 / ellipsoid.Ellipse.InvFlattening - - b := a * (1.0 - f) - e := math.Sqrt((a*a - b*b) / (a * a)) - esq := e * e // e squared - - if ellipsoid.Units == Degrees { - lat1 = deg2rad(lat1) - lon1 = deg2rad(lon1) - } - - h := alt1 // renamed for convenience - phi := lat1 - lambda := lon1 - - cphi := math.Cos(phi) - sphi := math.Sin(phi) - sphisq := sphi * sphi - clam := math.Cos(lambda) - slam := math.Sin(lambda) - N := a / (math.Sqrt(1 - esq*sphisq)) - x = (N + h) * cphi * clam - y = (N + h) * cphi * slam - z = ((b*b*N)/(a*a) + h) * sphi - - return x, y, z -} - -/* - DEFINED ELLIPSOIDS - -The following ellipsoids are defined in Geo::Ellipsoid, with the -semi-major axis in meters and the reciprocal flattening as shown. - - - Ellipsoid Semi-Major Axis (m.) 1/Flattening - --------- ------------------- --------------- - AIRY 6377563.396 299.3249646 - AIRY-MODIFIED 6377340.189 299.3249646 - AUSTRALIAN 6378160.0 298.25 - BESSEL-1841 6377397.155 299.1528128 - CLARKE-1880 6378249.145 293.465 - EVEREST-1830 6377276.345 290.8017 - EVEREST-MODIFIED 6377304.063 290.8017 - FISHER-1960 6378166.0 298.3 - FISHER-1968 6378150.0 298.3 - GRS80 6378137.0 298.25722210088 - HOUGH-1956 6378270.0 297.0 - HAYFORD 6378388.0 297.0 - IAU76 6378140.0 298.257 - KRASSOVSKY-1938 6378245.0 298.3 - NAD27 6378206.4 294.9786982138 - NWL-9D 6378145.0 298.25 - SOUTHAMERICAN-1969 6378160.0 298.25 - SOVIET-1985 6378136.0 298.257 - WGS72 6378135.0 298.26 - WGS84 6378137.0 298.257223563 - -plus a few more ... - - LIMITATIONS - -The methods should not be used on points which are too near the poles -(above or below 89 degrees), and should not be used on points which -are antipodal, i.e., exactly on opposite sides of the ellipsoid. The -methods will not return valid results in these cases. - -The Go-version does not support all features of the Perl module. If you -need advanced features, like defining your own ellipses at runtime, -calculating x,y dislocations, etc, please refer to the package on CPAN - -Geo::Ellipsoid - -http://search.cpan.org/~jgibson/Geo-Ellipsoid-1.12/lib/Geo/Ellipsoid.pm - -FIXME: Add more checks for div by 0. - - ACKNOWLEDGEMENTS - -The conversion algorithms used here are Perl translations of Fortran -routines written by LCDR L. Pfeifer NGS Rockville MD that implement -T. Vincenty's Modified Rainsford's method with Helmert's elliptical -terms as published in "Direct and Inverse Solutions of Ellipsoid on -the Ellipsoid with Application of Nested Equations", T. Vincenty, -Survey Review, April 1975. - -The Fortran source code files inverse.for and forward.for -may be obtained from - - ftp://ftp.ngs.noaa.gov/pub/pcsoft/for_inv.3d/source/ - - AUTHOR - -Jim Gibson, <Jim@Gibson.org> (Perl version) -Stefan Schroeder <ondekoza@gmail.com> (Port from Perl to Golang) - - BUGS - -See LIMITATIONS, above. - -Please report any bugs or feature requests to -the author. - -COPYRIGHT & LICENSE - -Copyright 2005-2008 Jim Gibson, all rights reserved. - -This program is free software; you can redistribute it and/or modify it -under the same terms as Perl. - -*/ |