coordinate 0.1.2 → 0.2
raw patch · 15 files changed
+90/−215 lines, 15 filesdep +HUnitdep +coordinatedep +papadep −QuickCheckdep −directorydep −doctestdep ~basedep ~lenssetup-changednew-uploaderPVP ok
version bump matches the API change (PVP)
Dependencies added: HUnit, coordinate, papa
Dependencies removed: QuickCheck, directory, doctest, filepath, template-haskell
Dependency ranges changed: base, lens
API changes (from Hackage documentation)
- Data.Geodetic.EllipsoidReaderT: instance Control.Lens.Wrapped.Wrapped (Data.Geodetic.EllipsoidReaderT.EllipsoidReaderT f0 a0)
- Data.Geodetic.EllipsoidReaderT: instance Data.Geodetic.EllipsoidReaderT.EllipsoidReaderT f0 a0 ~ t0 => Control.Lens.Wrapped.Rewrapped (Data.Geodetic.EllipsoidReaderT.EllipsoidReaderT f1 a1) t0
- Data.Geodetic.Sphere: instance Data.Geodetic.Sphere.Sphere ~ t0 => Control.Lens.Wrapped.Rewrapped Data.Geodetic.Sphere.Sphere t0
+ Data.Geodetic.EllipsoidReaderT: instance Control.Lens.Wrapped.Wrapped (Data.Geodetic.EllipsoidReaderT.EllipsoidReaderT f a)
+ Data.Geodetic.EllipsoidReaderT: instance Data.Geodetic.EllipsoidReaderT.EllipsoidReaderT f1 a1 ~ t => Control.Lens.Wrapped.Rewrapped (Data.Geodetic.EllipsoidReaderT.EllipsoidReaderT f2 a2) t
+ Data.Geodetic.Sphere: instance Data.Geodetic.Sphere.Sphere ~ t => Control.Lens.Wrapped.Rewrapped Data.Geodetic.Sphere.Sphere t
- Data.Geodetic.ECEF: class HasECEF c_ajBp where xy = (.) eCEF xy z = (.) eCEF z
+ Data.Geodetic.ECEF: class HasECEF c_alK1
- Data.Geodetic.ECEF: eCEF :: HasECEF c_ajBp => Lens' c_ajBp ECEF
+ Data.Geodetic.ECEF: eCEF :: HasECEF c_alK1 => Lens' c_alK1 ECEF
- Data.Geodetic.ECEF: xy :: HasECEF c_ajBp => Lens' c_ajBp XY
+ Data.Geodetic.ECEF: xy :: HasECEF c_alK1 => Lens' c_alK1 XY
- Data.Geodetic.ECEF: z :: HasECEF c_ajBp => Lens' c_ajBp Double
+ Data.Geodetic.ECEF: z :: HasECEF c_alK1 => Lens' c_alK1 Double
- Data.Geodetic.Ellipsoid: class HasEllipsoid c_aevt where flattening = (.) ellipsoid flattening semiMajor = (.) ellipsoid semiMajor
+ Data.Geodetic.Ellipsoid: class HasEllipsoid c_abp1
- Data.Geodetic.Ellipsoid: ellipsoid :: HasEllipsoid c_aevt => Lens' c_aevt Ellipsoid
+ Data.Geodetic.Ellipsoid: ellipsoid :: HasEllipsoid c_abp1 => Lens' c_abp1 Ellipsoid
- Data.Geodetic.Ellipsoid: flattening :: HasEllipsoid c_aevt => Lens' c_aevt Double
+ Data.Geodetic.Ellipsoid: flattening :: HasEllipsoid c_abp1 => Lens' c_abp1 Double
- Data.Geodetic.Ellipsoid: semiMajor :: HasEllipsoid c_aevt => Lens' c_aevt Double
+ Data.Geodetic.Ellipsoid: semiMajor :: HasEllipsoid c_abp1 => Lens' c_abp1 Double
- Data.Geodetic.LL: class HasLL c_ab2z where lat = (.) lL lat lon = (.) lL lon
+ Data.Geodetic.LL: class HasLL c_acnQ
- Data.Geodetic.LL: lL :: HasLL c_ab2z => Lens' c_ab2z LL
+ Data.Geodetic.LL: lL :: HasLL c_acnQ => Lens' c_acnQ LL
- Data.Geodetic.LL: lat :: HasLL c_ab2z => Lens' c_ab2z Double
+ Data.Geodetic.LL: lat :: HasLL c_acnQ => Lens' c_acnQ Double
- Data.Geodetic.LL: lon :: HasLL c_ab2z => Lens' c_ab2z Double
+ Data.Geodetic.LL: lon :: HasLL c_acnQ => Lens' c_acnQ Double
- Data.Geodetic.LLH: class HasLLH c_acTq where height = (.) lLH height
+ Data.Geodetic.LLH: class HasLLH c_adCH
- Data.Geodetic.LLH: height :: HasLLH c_acTq => Lens' c_acTq Double
+ Data.Geodetic.LLH: height :: HasLLH c_adCH => Lens' c_adCH Double
- Data.Geodetic.LLH: lLH :: HasLLH c_acTq => Lens' c_acTq LLH
+ Data.Geodetic.LLH: lLH :: HasLLH c_adCH => Lens' c_adCH LLH
- Data.Geodetic.XY: class HasXY c_adHD where x = (.) xY x y = (.) xY y
+ Data.Geodetic.XY: class HasXY c_akUl
- Data.Geodetic.XY: x :: HasXY c_adHD => Lens' c_adHD Double
+ Data.Geodetic.XY: x :: HasXY c_akUl => Lens' c_akUl Double
- Data.Geodetic.XY: xY :: HasXY c_adHD => Lens' c_adHD XY
+ Data.Geodetic.XY: xY :: HasXY c_akUl => Lens' c_akUl XY
- Data.Geodetic.XY: y :: HasXY c_adHD => Lens' c_adHD Double
+ Data.Geodetic.XY: y :: HasXY c_akUl => Lens' c_akUl Double
Files
- LICENCE +1/−0
- Setup.hs +2/−0
- Setup.lhs +0/−44
- changelog.md +5/−0
- coordinate.cabal +17/−18
- src/Data/Geodetic/ECEF.hs +1/−6
- src/Data/Geodetic/Ellipsoid.hs +1/−7
- src/Data/Geodetic/EllipsoidReaderT.hs +6/−47
- src/Data/Geodetic/HasDoubles.hs +1/−3
- src/Data/Geodetic/LL.hs +1/−23
- src/Data/Geodetic/LLH.hs +2/−7
- src/Data/Geodetic/Sphere.hs +1/−22
- src/Data/Geodetic/XY.hs +1/−6
- test/doctests.hs +0/−32
- test/hunit_tests.hs +51/−0
LICENCE view
@@ -1,4 +1,5 @@ Copyright 2013-2016 NICTA Limited+Copyright 2018, Commonwealth Scientific and Industrial Research Organisation (CSIRO) ABN 41 687 119 230. All rights reserved.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
− Setup.lhs
@@ -1,44 +0,0 @@-#!/usr/bin/env runhaskell-\begin{code}-{-# OPTIONS_GHC -Wall #-}-module Main (main) where--import Data.List ( nub )-import Data.Version ( showVersion )-import Distribution.Package ( PackageName(PackageName), PackageId, InstalledPackageId, packageVersion, packageName )-import Distribution.PackageDescription ( PackageDescription(), TestSuite(..) )-import Distribution.Simple ( defaultMainWithHooks, UserHooks(..), simpleUserHooks )-import Distribution.Simple.Utils ( rewriteFile, createDirectoryIfMissingVerbose )-import Distribution.Simple.BuildPaths ( autogenModulesDir )-import Distribution.Simple.Setup ( BuildFlags(buildVerbosity), fromFlag )-import Distribution.Simple.LocalBuildInfo ( withLibLBI, withTestLBI, LocalBuildInfo(), ComponentLocalBuildInfo(componentPackageDeps) )-import Distribution.Verbosity ( Verbosity )-import System.FilePath ( (</>) )--main :: IO ()-main = defaultMainWithHooks simpleUserHooks- { buildHook = \pkg lbi hooks flags -> do- generateBuildModule (fromFlag (buildVerbosity flags)) pkg lbi- buildHook simpleUserHooks pkg lbi hooks flags- }--generateBuildModule :: Verbosity -> PackageDescription -> LocalBuildInfo -> IO ()-generateBuildModule verbosity pkg lbi = do- let dir = autogenModulesDir lbi- createDirectoryIfMissingVerbose verbosity True dir- withLibLBI pkg lbi $ \_ libcfg -> do- withTestLBI pkg lbi $ \suite suitecfg -> do- rewriteFile (dir </> "Build_" ++ testName suite ++ ".hs") $ unlines- [ "module Build_" ++ testName suite ++ " where"- , "deps :: [String]"- , "deps = " ++ (show $ formatdeps (testDeps libcfg suitecfg))- ]- where- formatdeps = map (formatone . snd)- formatone p = case packageName p of- PackageName n -> n ++ "-" ++ showVersion (packageVersion p)--testDeps :: ComponentLocalBuildInfo -> ComponentLocalBuildInfo -> [(InstalledPackageId, PackageId)]-testDeps xs ys = nub $ componentPackageDeps xs ++ componentPackageDeps ys--\end{code}
changelog.md view
@@ -1,3 +1,8 @@+0.2++* Depend on papa+* Support GHC 8.4+ 0.1.2 * Functions to construct using degrees.
coordinate.cabal view
@@ -1,28 +1,28 @@ name: coordinate-version: 0.1.2+version: 0.2 license: BSD3 license-file: LICENCE author: Tony Morris <ʇǝu˙sıɹɹoɯʇ@ןןǝʞsɐɥ> maintainer: Tony Morris copyright: Copyright (C) 2013-2016 NICTA Limited+ Copyright (c) 2018, Commonwealth Scientific and Industrial Research Organisation (CSIRO) ABN 41 687 119 230.+ synopsis: A representation of latitude and longitude category: Development description: - <<http://i.imgur.com/Ns5hntl.jpg>>+ <<http://i.imgur.com/uZnp9ke.png>> . A representation of latitude and longitude-homepage: https://github.com/NICTA/coordinate-bug-reports: https://github.com/NICTA/coordinate/issues+homepage: https://github.com/qfpl/coordinate+bug-reports: https://github.com/qfpl/coordinate/issues cabal-version: >= 1.10-build-type: Custom+build-type: Simple extra-source-files: changelog.md, other-licence.md+tested-with: GHC == 8.4.1, GHC == 8.2.2, GHC == 8.0.2, GHC == 7.10.3 source-repository head type: git- location: git@github.com:NICTA/coordinate.git--flag small_base- description: Choose the new, split-up base package.+ location: git@github.com:qfpl/coordinate.git library default-language:@@ -30,8 +30,9 @@ build-depends: base >= 4 && < 5- , lens >= 4.0 && < 5.0+ , lens >= 4 && < 5 , transformers >= 0.4 && < 0.6+ , papa >= 0.3 && < 0.4 ghc-options: -Wall@@ -53,23 +54,21 @@ Data.Geodetic.Sphere Data.Geodetic.XY -test-suite doctests+test-suite hunit type: exitcode-stdio-1.0 main-is:- doctests.hs+ hunit_tests.hs default-language: Haskell2010 build-depends:- base < 5 && >= 3- , doctest >= 0.9.7- , filepath >= 1.3- , directory >= 1.1- , QuickCheck >= 2.0- , template-haskell >= 2.8+ base >= 3 && < 5+ , coordinate+ , HUnit >= 1.2 && < 1.7+ , lens >= 4 && < 5 ghc-options: -Wall
src/Data/Geodetic/ECEF.hs view
@@ -6,14 +6,9 @@ , HasECEF(..) ) where -import Control.Applicative(Applicative((<*>)))-import Control.Lens(makeClassy, lens)-import Data.Eq(Eq)-import Data.Functor((<$>)) import Data.Geodetic.HasDoubles(HasDoubles(doubles)) import Data.Geodetic.XY(XY, HasXY(xY))-import Data.Ord(Ord)-import Prelude(Show, Double)+import Papa data ECEF = ECEF {
src/Data/Geodetic/Ellipsoid.hs view
@@ -23,14 +23,8 @@ , clarke1880 ) where -import Control.Applicative(Applicative((<*>)))-import Control.Category((.))-import Control.Lens(makeClassy, Lens', involuted)-import Data.Eq(Eq)-import Data.Functor((<$>)) import Data.Geodetic.HasDoubles(HasDoubles(doubles))-import Data.Ord(Ord)-import Prelude(Show, Double, (/))+import Papa data Ellipsoid = Ellipsoid {
src/Data/Geodetic/EllipsoidReaderT.hs view
@@ -25,28 +25,21 @@ , earthGeo ) where -import Control.Category((.))-import Control.Applicative(Applicative((<*>), pure), liftA2, Alternative((<|>), empty))-import Control.Lens(makeWrapped, (#), _Unwrapped, ReifiedIso', ReifiedIso(Iso), Iso', iso, from, (^.), (&), Wrapped(_Wrapped'))-import Control.Monad(Monad((>>=), return), MonadPlus(mzero, mplus))+import Control.Applicative(Alternative((<|>), empty), liftA2)+import qualified Control.Monad as Monad(return, (>>=))+import Control.Monad(MonadPlus(mzero, mplus)) import Control.Monad.Fix(MonadFix(mfix)) import Control.Monad.IO.Class(MonadIO(liftIO)) import Control.Monad.Trans.Class(MonadTrans(lift)) import Control.Monad.Trans.Reader(ReaderT) import Control.Monad.Zip(MonadZip(mzip))-import Data.Functor(Functor(fmap), (<$>)) import Data.Functor.Identity(Identity(Identity, runIdentity)) import Data.Geodetic.ECEF(ECEF(..), HasECEF(z)) import Data.Geodetic.Ellipsoid(Ellipsoid, HasEllipsoid(semiMajor, flattening), flatteningReciprocal, wgs84) import Data.Geodetic.LL(LL(LL), HasLL(lat, lon)) import Data.Geodetic.LLH(LLH(LLH), HasLLH(height)) import Data.Geodetic.XY(XY(XY), HasXY(x, y))-import Data.Int(Int)-import Prelude(Double, Num((*), (+), (-)), Fractional((/)), Floating(sin, cos, sqrt, atan, (**)), RealFloat(atan2), (^))---- $setup--- >>> import Control.Lens(ReifiedIso(runIso))--- >>> import Data.Geodetic.Ellipsoid+import Papa newtype EllipsoidReaderT f a = EllipsoidReaderT (Ellipsoid -> f a)@@ -98,9 +91,9 @@ instance Monad f => Monad (EllipsoidReaderT f) where return =- EllipsoidReaderT . return . return+ EllipsoidReaderT . Monad.return . Monad.return EllipsoidReaderT k >>= f =- EllipsoidReaderT (\e -> k e >>= \q -> e & f q ^. _Wrapped')+ EllipsoidReaderT (\e -> k e Monad.>>= \q -> e & f q ^. _Wrapped') instance Alternative f => Alternative (EllipsoidReaderT f) where empty =@@ -162,20 +155,12 @@ readFlatteningReciprocal <*> readSemiMajor --- |------ >>> wgs84' eccentricitySquared--- 6.6943799901413165e-3 eccentricitySquared :: Applicative f => EllipsoidReaderT f Double eccentricitySquared = (\f -> 2 * f - (f * f)) <$> readFlatteningReciprocal --- |------ >>> wgs84' eccentricitySquared'--- 6.694455244784511e-3 eccentricitySquared' :: Applicative f => EllipsoidReaderT f Double@@ -189,19 +174,6 @@ distributeNormal t = (\k -> k t) <$> normal --- |------ >>> wgs84' normal 7--- 6387371.845852088------ >>> wgs84' normal 71--- 6397535.266650572------ >>> wgs84' normal 711--- 6393308.675975408------ >>> wgs84' normal (-7)--- 6387371.845852088 normal :: Applicative f => EllipsoidReaderT f (Double -> Double)@@ -220,19 +192,6 @@ wgs84'' r = (_Unwrapped # r) wgs84 --- |------ >>> ECEF (XY (-5019624) 2618621) (-2927516) ^. runIso (wgs84' earthGeo)--- LLH {ll = LL {_lat = -0.4799654447089294, _lon = 2.66075442877903}, _height = 100.20987554546446}------ >>> ECEF (XY 9919623 (-3116612)) (-2396517) ^. runIso (wgs84' earthGeo)--- LLH {ll = LL {_lat = -0.22740831363634992, _lon = -0.30442061911398305}, _height = 4293252.6636643605}------ >>> LLH (LL 0.48 2.661) 100 ^. from (runIso (wgs84' earthGeo))--- ECEF {_xy = XY {_x = -5020176.908575072, _y = 2617341.3240995244}, _z = 2927710.5079646683}------ >>> LLH (LL (-0.22741) (-0.30442)) 4293252.66 ^. from (runIso (wgs84' earthGeo))--- ECEF {_xy = XY {_x = 9919621.069754401, _y = -3116604.645933256}, _z = -2396534.4668575544} earthGeo :: Applicative f => EllipsoidReaderT f (ReifiedIso' ECEF LLH)
src/Data/Geodetic/HasDoubles.hs view
@@ -5,9 +5,7 @@ HasDoubles(..) ) where -import Control.Category(id)-import Control.Lens(Traversal')-import Prelude(Double)+import Papa class HasDoubles a where doubles ::
src/Data/Geodetic/LL.hs view
@@ -8,16 +8,8 @@ , (<◦>) ) where -import Control.Applicative(Applicative((<*>)))-import Control.Lens(makeClassy, Iso', iso, (^.))-import Data.Eq(Eq)-import Data.Functor((<$>)) import Data.Geodetic.HasDoubles(HasDoubles(doubles))-import Data.Ord(Ord)-import Prelude(Fractional((/)), Show, Double, pi, Num((*)))---- $setup--- >>> import Control.Lens+import Papa data LL = LL {@@ -36,13 +28,6 @@ f a <*> f o --- |------ >>> ((27.34, 152.15) ^. degrees)--- LL {_lat = 0.47717301749524965, _lon = 2.6555184569093724}------ >>> (degrees # LL 0.47717 2.65552)--- (27.33982711025749,152.15008841258037) degrees :: Iso' (Double, Double)@@ -54,13 +39,6 @@ (\(LL t n) -> let r a = a / pi * 180 in (r t, r n)) --- |------ >>> 27.34 <◦> 152.15--- LL {_lat = 0.47717301749524965, _lon = 2.6555184569093724}------ >>> 61.94 <◦> (-152.15)--- LL {_lat = 1.0810569386852877, _lon = -2.6555184569093724} (<◦>) :: Double -> Double
src/Data/Geodetic/LLH.hs view
@@ -6,14 +6,9 @@ , HasLLH(..) ) where -import Control.Applicative(Applicative((<*>)))-import Control.Lens(makeClassy, lens)-import Data.Eq(Eq)-import Data.Functor((<$>)) import Data.Geodetic.HasDoubles(HasDoubles(doubles))-import Data.Geodetic.LL-import Data.Ord(Ord)-import Prelude(Show, Double)+import Data.Geodetic.LL(HasLL(lL), LL)+import Papa data LLH = LLH {
src/Data/Geodetic/Sphere.hs view
@@ -10,15 +10,8 @@ , ellipsoidSphere ) where -import Control.Lens(makeWrapped, Prism', prism')-import Data.Eq(Eq((==)))-import Data.Maybe(Maybe(Just, Nothing))-import Data.Ord(Ord) import Data.Geodetic.Ellipsoid(Ellipsoid(Ellipsoid))-import Prelude(Double, Show)---- $setup--- >>> import Control.Lens+import Papa newtype Sphere = Sphere Double@@ -26,25 +19,11 @@ makeWrapped ''Sphere --- |------ >>> earthMean--- Sphere 6367450.0 earthMean :: Sphere earthMean = Sphere 6367450 --- |------ >>> ellipsoidSphere # Sphere 77--- Ellipsoid {_semiMajor = 77.0, _flattening = 1.0}------ >>> Ellipsoid 77 1 ^? ellipsoidSphere--- Just (Sphere 77.0)------ >>> Ellipsoid 77 2 ^? ellipsoidSphere--- Nothing ellipsoidSphere :: Prism' Ellipsoid
src/Data/Geodetic/XY.hs view
@@ -6,13 +6,8 @@ , HasXY(..) ) where -import Control.Applicative(Applicative((<*>)))-import Control.Lens(makeClassy)-import Data.Eq(Eq)-import Data.Functor((<$>)) import Data.Geodetic.HasDoubles(HasDoubles(doubles))-import Data.Ord(Ord)-import Prelude(Show, Double)+import Papa data XY = XY {
− test/doctests.hs
@@ -1,32 +0,0 @@-module Main where--import Build_doctests (deps)-import Control.Applicative-import Control.Monad-import Data.List-import System.Directory-import System.FilePath-import Test.DocTest--main ::- IO ()-main =- getSources >>= \sources -> doctest $- "-isrc"- : "-idist/build/autogen"- : "-optP-include"- : "-optPdist/build/autogen/cabal_macros.h"- : "-hide-all-packages"- : map ("-package="++) deps ++ sources--getSources :: IO [FilePath]-getSources = filter (isSuffixOf ".hs") <$> go "src"- where- go dir = do- (dirs, files) <- getFilesAndDirectories dir- (files ++) . concat <$> mapM go dirs--getFilesAndDirectories :: FilePath -> IO ([FilePath], [FilePath])-getFilesAndDirectories dir = do- c <- map (dir </>) . filter (`notElem` ["..", "."]) <$> getDirectoryContents dir- (,) <$> filterM doesDirectoryExist c <*> filterM doesFileExist c
+ test/hunit_tests.hs view
@@ -0,0 +1,51 @@+module Main (main) where++import Test.HUnit (Assertion, Test (TestCase, TestList), (@?=), runTestTT, failures, errors)++import Prelude+import Control.Lens ((^.), (^?), (#), ReifiedIso(runIso), from)+import Control.Monad (when)+import System.Exit (exitFailure)++import Data.Geodetic.ECEF+import Data.Geodetic.Ellipsoid+import Data.Geodetic.EllipsoidReaderT+import Data.Geodetic.LL+import Data.Geodetic.LLH+import Data.Geodetic.Sphere+import Data.Geodetic.XY++(@??=) :: Show a => a -> a -> Assertion+a @??= b = show a @?= show b+infix 1 @??=++assertions :: [Assertion]+assertions =+ [ wgs84' eccentricitySquared @??= 6.6943799901413165e-3+ , wgs84' eccentricitySquared' @??= 6.694455244784511e-3+ , wgs84' normal 7 @??= 6387371.845852088+ , wgs84' normal 71 @??= 6397535.266650572+ , wgs84' normal 711 @??= 6393308.675975408+ , wgs84' normal (-7) @??= 6387371.845852088+ , ECEF (XY (-5019624) 2618621) (-2927516) ^. runIso (wgs84' earthGeo) @?= LLH {ll = LL {_lat = -0.4799654447089294, _lon = 2.66075442877903}, _height = 100.20987554546446}+ , ECEF (XY 9919623 (-3116612)) (-2396517) ^. runIso (wgs84' earthGeo) @?= LLH {ll = LL {_lat = -0.22740831363634992, _lon = -0.30442061911398305}, _height = 4293252.6636643605}+ , LLH (LL 0.48 2.661) 100 ^. from (runIso (wgs84' earthGeo)) @?= ECEF {_xy = XY {_x = -5020176.908575072, _y = 2617341.3240995244}, _z = 2927710.5079646683}+ , LLH (LL (-0.22741) (-0.30442)) 4293252.66 ^. from (runIso (wgs84' earthGeo)) @?= ECEF {_xy = XY {_x = 9919621.069754401, _y = -3116604.645933256}, _z = -2396534.4668575544}+ , ((27.34, 152.15) ^. degrees) @?= LL {_lat = 0.47717301749524965, _lon = 2.6555184569093724}+ , (degrees # LL 0.47717 2.65552) @?= (27.33982711025749,152.15008841258037)+ , 27.34 <◦> 152.15 @?= LL {_lat = 0.47717301749524965, _lon = 2.6555184569093724}+ , 61.94 <◦> (-152.15) @?= LL {_lat = 1.0810569386852877, _lon = -2.6555184569093724}+ , earthMean @?= Sphere 6367450.0+ , ellipsoidSphere # Sphere 77 @?= Ellipsoid {_semiMajor = 77.0, _flattening = 1.0}+ , Ellipsoid 77 1 ^? ellipsoidSphere @?= Just (Sphere 77.0)+ , Ellipsoid 77 2 ^? ellipsoidSphere @?= Nothing+ ]++tests :: Test+tests =+ TestList $ fmap TestCase assertions++main :: IO ()+main = do+ c <- runTestTT tests+ when (errors c > 0 || failures c > 0) exitFailure