Commit Graph

79 Commits

Author SHA1 Message Date
Shams Asari
48f58b6dbc Introducing StartableByRPC and SchedulableFlow annotations, needed by flows started via RPC and schedulable flows respectively.
CordaPluginRegistry.requiredFlows is no longer needed as a result.
2017-05-11 14:55:40 +01:00
Ross Nicoll
e4a0bc6e11 Move party classes into identity package
Move AbstractParty, AnonymousParty and Party into a new net.corda.core.identity package,
as they're not really cryptography tools, and in preparation for further code coming in
for identity.

Optimize imports on many files to clean up the resulting refactor.
2017-05-11 11:25:59 +01:00
Andras Slemmer
de88ad4f40 RPC muxing, multithreading, RPC driver, performance tests 2017-05-05 17:10:52 +01:00
Ross Nicoll
25dbac0f07 Change party to hold an X.500 name
Change the legal name of parties to be an X500 name. This ensures that we aren't converting between
common names and X500 names in various places, eliminating substantial scope for error in the conversion
process. As a result, all node names must now be full X500 names, which has impact on most configurations.
2017-05-05 16:13:29 +01:00
Katarzyna Streich
c062d48e6e Explorer x500names (#631)
Format party names in explorer, so they look nice after X500 name changes.
2017-05-05 14:00:55 +01:00
Chris Rankin
0309426cb9 Include log4j2.xml into application jars only. This allows applications to use their own log4j2.xml files, if required. (#635) 2017-05-05 13:12:36 +01:00
Ross Nicoll
e85ed639bb Clean up X500 names in Corda simulation
Clean up X500 names in Corda simulation, and ensure they're consistent with the standard test names.
This includes using the locations present in those test names, which requires updates to the node
config test.
2017-05-03 15:55:19 +01:00
Ross Nicoll
d65d63e4f6 Interim patch introducing X500Names
This is an intermediary step to introducing X500Names in all Party instances, which adds:

* Party constructor which accepts X500Name and then converts it to string.
* startNode() function which takes in X500Name instead of String
* Numerous legal name fixes to use full distinguished names
2017-05-03 10:46:03 +01:00
Matthew Nesbit
7e3b9a8934 Fix duplicate content root problems in IntelliJ 2017-04-26 10:37:16 +02:00
Shams Asari
b5e022f350 Introducing Platform Version and its use by the NMS for min version requirements for the network 2017-04-24 15:31:10 +01:00
Andrzej Cichocki
160d13b6f7 Prohibit Java deserialisation in the Corda process (#566) 2017-04-21 16:26:35 +01:00
Chris Rankin
d2d7cbc9ec CORDA-299: Remove progress Observable from FlowHandle, unless explicitly requested. (#513)
* Remove progress Observable from FlowHandle, unless explicitly requested.
* Refactor FlowHandle creation into FlowStateMachine.
* Prevent server-side queue subscription for dummy Observable.
* Refactor so that RPC client does not receive any unused progress Observables. This is the simplest way of ensuring we have no dangling "hot" Observables when the RPC client closes.
* Test flow has correct handle.
* Resolve some compiler warnings.
* Document how starting a flow does not involve progress tracking by default.
* Update changelog and release notes for RPC API.
* Rename new RPC API to startTrackedFlow().
* Remove optimisation because of its affect on the client-side.
* Update documentation.
2017-04-19 20:11:51 +01:00
Ross Nicoll
d35bd74596 Standardise identities used in tests, demos, etc.
Standaridise the identity names of Alice, Bob and Charlie, notary, map service, etc. in order
to ensure consistency across the code base and reduce number of places that have to be changed
to introduce proper X.500 names.

Move Alice, Bob & Charlie identities into the utilities package so they can be used in demos
2017-04-12 11:40:48 +01:00
kasiastreich
36d5d0d7b2 Refactor of CompositeKeys to implement PublicKey interface. (#433)
* Make CompositeKey implement PublicKey

The initial implementation of composite keys as their own distinct class separate from PublicKey
means that the keys cannot be used on standard classes such as Certificate. This work is a beginning
to modifying CompositeKey to being a PublicKey implementation, although significant further work
is required to integrate this properly with the standard Java APIs, especially around verifying
signatures using the new key type.

* First stage of making CompositeKey implement PublicKey interface. Revert to using PublicKey everywhere we expect a key.

* Move algorithm and format into companion object (#432)

Move algorithm and format into companion object so that they can be referenced from other
classes (i.e. the upcoming signature class).

* Add simple invariants to construction of CompositeKey.
Builder emits CompositeKeys in simplified normalised form. Forbid keys with single child node, force ordering on children and forbid duplicates on the same level. It's not full semantical normalisation.

* Make constructor of CompositeKey private, move NodeWeight inside the class.
Add utility function for Kryo deserialization to read list with length constraints.
2017-04-12 11:13:20 +01:00
Mike Hearn
0c0c5521c0 Minor: address more formatting issues spotted by Shams 2017-04-11 15:53:05 +02:00
Mike Hearn
4853e41a58 Minor: inspector fixes 2017-04-11 15:53:05 +02:00
Mike Hearn
c097229935 Minor: run code cleanup inspections 2017-04-11 15:53:05 +02:00
Mike Hearn
4d6d4c167e Minor: auto-format of module: tools, verifier 2017-04-11 15:53:05 +02:00
Shams Asari
e0c548d4fa Cleaned up code causing build warnings 2017-04-03 13:52:51 +01:00
Matthew Nesbit
51c7f6ca30 Merge pull request #453 from corda/mnesbit-amount-improvements
Modify the Amount concept to allow conversion to from displayable formats
2017-03-31 14:37:32 +01:00
Patrick Kuo
d8370a41b5 Reduce occurrence of flow exception in explorer demo (#467)
* changed event generator to reduce flow exception due to wrongly generated event
2017-03-31 14:19:02 +01:00
Konstantinos Chalkias
d72b75caa4 Observable.subscribe().unsubscribe() and ListenableFuture.cancel() (#397)
Observable.subscribe().unsubscribe() dance to free up the MQ resources server-side.

* remove an unused import

* implement a FlowHandle<Transaction>.finalize method

* Rename finalize() to discard() - remove the collection and run discard individually

* Remove unused imports

* Observable.notUsed helper function

* Tweaks to comments

* FlowHandle implements AutoClosable

* Resolving conflicts and move notUsed to RPC module

* Copy Observable.notUsed in core module.

* delete discard method
2017-03-31 10:08:12 +01:00
Chris Rankin
f15a22d828 Replace kotlinx-support-jdk8 with kotlin-stdlib-jre8. (#463)
* Replace kotlinx-support-jdk8 with kotlin-stdlib-jre8.
* Add kotlinVersion to constants.properties.

* Remove unused variable.
2017-03-30 16:27:01 +01:00
Matthew Nesbit
cedfc4e1ad Add a concept of token size to Amount<T> so that conversion to/from indicative and displayable BigDecimal works sensibly
Add an AmountTransfer type to express the concept of asset flows.

Unify the currency amount creators and fix a few old style display conversions in teh explorer cash dialogs.

Modifications according to PR comments.

Change TransferAmount display string as it may not always be a payment.

Update docs
2017-03-30 16:16:11 +01:00
Matthew Nesbit
062dc67ab6 Add Any constraint to Amount token
Signed-off-by: Ross Nicoll <ross.nicoll@r3.com>
2017-03-29 17:11:30 +01:00
Patrick Kuo
9a7d0a0fb5 Replace unused variables with _ after kotlin 1.1.1 upgrade (#456)
* Replace unused variables with _ after kotlin 1.1.1 upgrade
2017-03-29 13:54:40 +01:00
Rick Parker
8ef1d767c9 Consolidate maven repositories (#445)
* Consolidate repositories into root build.gradle
2017-03-28 17:17:40 +01:00
josecoll
0280299104 Soft locking implementation using database coin selection
Fix broken IssuerFlowTest

Fix IssuerFlowTests after rebase.

Resolve conflicts after rebase.

Soft locking converted to use persistent store.
Added additional optional 'includeLockStates' parameter in VaultService states API call.
Added Vault softLocked states query API call.

Fixed commercial paper failing test.
Improved exception handling on soft locking UPDATE statement.

Using SELECT FOR UPDATE to ensure correct soft locking data visibility.
Db query operations moved out of mutex code (as locking managed by underlying DB)

Adjusted logging severity levels.

Adjusted logging severity levels.

GenerateSpending now performing fine grained query for unconsumed states by joining with contract_cash_states table.
Using H2 proprietary cummulative counting feature (using sessioni SET variables)
Refactored and simplified HibernateObserver constructor to enable usage in JUnit tests.

Event generator issues larger random amounts (10,000..1,000,000) to those than are spent (0..10,000)
Adjusted Issue (5:1) and Exit (10:1) generation frequency vs spending.

Minor fixes: added optional lockid into select for spending criteria, set notary, additional trace logging.

Generate Cash Schema by default upon node start-up (as part of NodeSchemaService initialisation).

Explicitly close JDBC statements in finally() blocks.

Tightened HibernateObserver constructor.

Fix CommercialPaper test (was missing auto-generation of CONTRACT_CASH table)

Revert default JVM size back to 200Mb.

Revert default number of iterations in Explorer Node Simulation mode (back to 10000 with .5 sec sleep interval).

Remove redundant setter function.

Added TODO messages indicating Requery / H2 restrictions & caveats.

Consumed states lock updates now performed in general consumed state Update.

Updated/added Soft Locking documentation.

Addressed initial PR comments: use THREAD_LOCAL_KRYO, use AbstractParty, extract helper method, improve readability, address some doc typos

Addressed PR comment: removed lockId from WireTransaction.

Fixed soft locking UPDATE statements.

Improvements to VaultSoftLockManager for auto-registration of soft locks for flows with spendable states (as notifications from vault).
Other optimisations (IssuerFlow no longer explicitly reserve/release issued state) and improvements (soft lock release management of soft locks, docs update)

Performance update: now using Requery for UPDATE in release soft locking (non-composite key statement)

Removed redundant TODO messages (TODO: revisit Kryo bug when using THREAD_LOCAL_KYRO)

Minor fixes following rebase

Fixed failing JUnit following rebase

Addressed MH PR review items (1st pass)

Fix broken JUnit

Significant changes to RDBMS operations within coin selection and soft locking as requested by PR review.
(Removed SELECT FOR UPDATE; added RETRY upon coin selection; reverting partial soft locks)

Addressed a number of PR review requests added by MH (comments/spelling, lockID instantiation, HibernateObserver instantiation, cash schema white-listing usage)

Addressed latest PR review comments from RP.

Minor fixes following rebase from master.

Fixed final failing JUnit (issuer flow concurrent).

Updated TraderDemo to trigger concurrent issuance of cash.

Fixed compiler warning on lockId null check.

Fixed subtle bug in coin selection intermittently surfaced in IntegrationTestTutorial.

Fixed small memory leak.

Removed stray } in logger trace message.

Slight rewording of description of Soft Locking in docs.

Renamed NoStatesAvailableException to StatesNotAvailableException.
generateSpend is now Suspendable (calls sleep method on flow upon coin selection retry).

Added companion function to enable a Strand to sleep but without locking transactional context.

Improved logging, changed to StateNotAvailableException, using Flow sleep upon retry, tweaked SELECT criteria in coin selection, fixed bug when insufficient states selectable, generateSpend is now @suspendable

Improved handling and logging of flow results in Simulation Mode.

Fixed minor error in sleep when not an active flow.

Retry coin selection when unavailable states (as these may become available as new states).
Additional debug logging to highlight and identify H2 coin selection sporadic bug.

Inlined sleep method due to intermittent Quasar error.

Re-introduce selection clause that prevents selection and temporary locking of already locked states (by other flows).
Improved trace logging for coin selection (SQL row level info).
Correctly calling FlowStateMachineImpl sleep (now inlined and working correctly)

Fixed rebase error.

Remove redundant TODO message.
2017-03-27 17:12:33 +01:00
Chris Rankin
98266da41c Refactor CordaRPCClient into new :client:rpc Gradle module. (#405)
* CORDA-305: Refactor CordaRPCClient into :client:rpc module

* CORDA-305: Remove the Kotlin test framework from the artifacts.

* CORDA-305: Migrate serialisation whitelist into node-api module.

* CORDA-305: Clean up unused RPC observables.

* CORDA-305: Add :client:rpc module to documentation tasks.

* CORDA-305: Include :finance into :client:rpc for its serialisable classes.

* CORDA-305: Move test classes into the correct directory.

* CORDA-305: Migrate :finance dependency from :client:rpc into DemoBench.

* CORDA-305: Update wording of TODO about handling Observables.
2017-03-22 15:52:54 +00:00
Ross Nicoll
4f0e8b73bb Update port numbers in explorer docs 2017-03-22 12:25:36 +01:00
Chris Rankin
9e43df36d3 Refactor :client module into :client:javafx and :client:mock (#388)
* CORDA-304: Refactor :client modules into :client:javafx and :client:mock.

* CORDA-304: Add :client:mock to Dokka tasks, and remove unused integrationTest task.

* CORDA-304: Migrate DriverBasedTest from node into test-utils.

* CORDA-304: Rename .fx. package to .jfx. to prevent confusion with "exchange rate".

* CORDA-304: Rename module to ':client:jfx'.
2017-03-21 19:45:12 +00:00
Chris Rankin
18c57cf951 Merge DemoBench into Corda. (#380)
* Add basic spec for the demobench tool.

* Initial commit: Creating new tabs whenever the "Add Node" button is pressed. These tabs currently contain the bash shell only.

* Refactor shutdown code, although AWT is still misbehaving.

* Remove duplicate libpty native objects.

* Add initial form for configuring new nodes.

* Update to Corda 0.8-SNAPSHOT

* Patch JediTerm to allow the application to shutdown cleanly.

* Write configuration parameters into node.conf, and then run corda.jar in its own directory.

* The first node now becomes the session's Network Map service used by all other nodes. Force nodes to be created one-by-one.

* Trim node name and nearest city values.

* Fix logging location of corda.jar

* legalName field can be val.

* Allow configuration of extra network services.

* Launch DB viewer for node.

* Small tidy-up.

* Allow services to be loaded as a resources as well as a file.

* Include native artifacts in distribution.

* Add cash and issuer services to DemoBench.

* Configure Node and DemoBench to use same version of H2 database.

* Implement launching "Node Explorer" for each node.

* Create a capsule for Node Explorer, and allow login via command line parameters to bypass login screen.

* Simplify Kotlin objects.

* Include issuer for CHF (Swiss Francs)

* Fix SLF4J logging.

* Display simple statistics about the node on each tab.

* Add new RPC operation getCashBalances() to Node.

* Ensure demobench is built after explorer:capsule.

* Grant permissions to the Node's user, and install BanfOfCorda plugin for cash issuers.

* Initial inclusion of Corda and BankOfCorda JARs in distribution.

* Fix DemoBench distribution target.

* Add SLF4J binding for Log4J 2.x

* First batch of code review changes.

* More changes from review.

* Remove ".exe" from Java executable path, because Windows doesn't need it.

* Remove superfluous lamba parameter names.

* Better usage of Paths vs File API.

* Simplify the configuration object.

* Ensure a DemoBench installation is relocatable.

* Ensure that Node Explorer can write into its working directory.

* Disable Node Explorer and Database Viewer buttons until the node has launched and is responding to RPC.

* Only allow the first node to run notary services. And validate port numbers more strongly.

* Force all chosen port numbers to be different.

* Initial javapackager task: currently builds RPMs.

* Ensure JavaPackager task finds custom resources on the classpath.

* Move demobench.log into the user's demobench directory.

* Upgrade to Logback 1.1.10

* Make the javapackage task "more gradle" and "less ant".

* Display "0" balance for a node which has no cash balances at all.

* CORPRIV-665: Ensure tab closes if the node exits.

* CORPRIV-665: Protect against NPE

* CORPRIV-665: Protect harder against NPE

* CORPRIV-665: Protect NodeTerminalView from being destroyed twice.

* Initial custom resource script for Windows bundle.

* Take java executable from JRE.

* Allow Node Explorer to be relaunched.

* CORPRIV-658: Add gradle parameter "packageType" for javapackage task.

* Replace R3 logo with Corda logo.

* CORPRIV-658: Add icon file for Windows installer.

* CORPRIV-658: Add BAT file to create unsigned DemoBench.exe.

* CORPRIV-659: Add icon file for DMG package.

* Improve packaging information.

* CORPRIV-660: Allow user to launch Web server for each node.

* Tidy up gradle usage.

* Document provenance of jediterm-terminal-2.5.jar.

* Use "safe" casting operator.

* CORPRIV-659: Add bin/java to minimal JRE.

* CORPRIV-659: Basic shell script to package DemoBench as DMG.

* Add utility function for creating SLF4J loggers, and close unused I/O streams from forked processes.

* Switch from Runtime.exec() to ProcessBuilder.

* CORPRIV-660: Display Web server's port number on launch button.

* CORPRIV-661: Allow profiles to be loaded into DemoBench.

* Upgrade to TornadoFX 1.6.2.

* CORPRIV-661: Implement saving profiles.

* CORPRIV-661: Refactor code for guaranteeing a .zip extension.

* CORRIV-658: Add icon for Windows installer.

* CORPRIV-659: Update installer script and icons for DMG.

* CORPRIV-659: Tweak post-image script for DMG.

* CORPRIV-658: I've wasted enough time on this - Windows rejects this BMP
as invalid, and I have no idea why!?

* CORPRIV-658: Add external manifest for DemoBench.exe that declares it incapable of native HiDPI support.

* CORPRIV-661: Ensure that we can rewrite saved profiles correctly.

* Fix terminal resizing.

* CORPRIV-659: Fix DMG installer.

* CORPRIV-659: Better validation for JAVA_HOME.

* Downgrade JDK requirement to 8u102, for consistency with capsules.

* Comment how JediTerm is not available via Maven.

* CORPRIV-658: Rename packaging script.

* CORPRIV-659: Renaming packaging script.

* Comment file copying vs file filtering during packaging.

* Fixes from code review.

* CORPRIV-661: Ensure that nodes loaded from a profile have the correct network map service.

* Break textfield definitions out into separate functions.

* Fixes from code review.

* Code review tweaks.

* More code review tweaks.

* Another simple code review tweak.

* Replace companion object with a BiPredicate lambda.

* CORPRIV-664: Implement saving/loading of Cordapps with profiles.

* CORPRIV-664: Refactor saving/loading plugins.

* CORPRIV-664: Add initial unit tests for model.

* CORPRIV-664: Add simple unit tests for NodeController.

* CORPRIV-664: Unit test enhancements, e.g. configure JUL properly.

* CORPRIV-664: Use Suite instead of abstract test class.

* CORPRIV-664: Allow Cordapps to be loaded when each Node is configured.

* CORPRIV-664: Document which checked Java exceptions are thrown.

* Write JavaPackager output into build/javapackage directory.

* CORPRIV-664: Document more checked Java exceptions.

* Refactor Web and Explorer classes into their own packages.

* Declare WebServer and Explorer constructors as "internal".

* Update packaging scripts: tell user where the installer is!

* CORPRIV-659: Set "system menu bar" property for MacOSX.

* CORPRIV-661: Use "*.profile" for profile files.

* Remove unnecessary <children/> elements, as they are defaults.

* Fix build breakage when on Windows.

* Tweaks for EXE packaging script.

* Change function to extension function.

* Merged in corpriv-702 (pull request #25)

CORPRIV-702: Sign the DMG with a 'Developer ID Application' certificate.

* CORPRIV-702: Sign the DMG with a 'Mac Developer' certificate.

* CORPRIV-702: Use "Developer ID Application" certificate instead. And now JavaPackager signs the application, which means that we only need to resign our embedded JVM.

* CORPRIV-702: Update comment better to explain why JRE must be resigned.

Approved-by: Mike Hearn

* Exclude old version of Javassist in favour of Hibernate's version from Node. (#320)

* Exclude old version of Javassist in favour of Hibernate's version.

* Comment why we are excluding javassist:javassist, and add TODO for when junit-quickcheck 0.8 is released.

* CORDA-265: Implement "ALL" permission for RPC users. (#306)

* CORDA-265: Implement "ALL" permission for RPC users. Users with this permission in node.conf can use any flow.

* CORDA-265: Ensure that we always close the RPC proxy object after each test.

* CORDA-265: Refactor construction of dummy RPC client into an abstract base class.

* CORDA-265: Document RPC "ALL" permission.

* CORDA-266: Update DemoBench to be compatible with 0.10-SNAPSHOT.

* CORDA-268: Reimplement to work on both JDK8 and JDK9 (for now).

* CORDA-268: Copy java from $JAVA_HOME/bin as this also works on JDK > 8.

* Code review fixes.

* Use SLF4J's version of the commons-logging bindings. Only include SLF4J's Log4J back-end for actual applications, e.g. Node. (#350)

* Update with SLF4J change.

* CORDA-266: Update to latest node.conf format.

* Upgrade to H2 1.4.194. (#389)

- Timezone related fixes.
- A Turkish case canonicalisation bug.
- Fixes for some scary threading related bugs.
2017-03-21 14:24:13 +00:00
Konstantinos Chalkias
0aecae6531 issuerNodeUSD fix
Small correction on issuerClientUSD = issuerNodeUSD.rpcClientToNode(), causing 'exiting more cash than exists' errors.
2017-03-20 14:47:52 +00:00
Mike Hearn
afbc8f9b5c De-issuerify the cash payment flow. This makes it easier to use the payment flow from the shell. 2017-03-20 15:14:28 +01:00
Andras Slemmer
c3c1f3d801 Add :node-api, factor out some artemis code 2017-03-17 11:47:05 +00:00
Ross Nicoll
486368d926 Clean up messaging/RPC port configuration and docs (#296)
* Non-ssl artemis acceptor for RPC connection. (#271)

* New non-ssl acceptor in artemis server for RPC connection.

* Rename artemisAddress with messagingAddress

Rename artemisAddress with messagingAddress so that the node configuration file properties match
the code variable names.
Rename artemisPort to messagingPort in Gradle configuration to match node configuration naming.

* Add rpcPort configuration option for Gradle

* Update docs to reflect changes to RPC port configuration

* Renumber ports in example CorDapp to match numbering used elsewhere

* Restructure upgrade guide

* added config file checks on corda startup to make the upgrade path a bit smoother.
2017-03-17 10:32:14 +00:00
Chris Rankin
bea256caf1 Use the project's version of Kotlin to build Explorer. (#351) 2017-03-13 11:44:21 +00:00
Patrick Kuo
570b871524 Bug Fixes [CORDA-282] - TX id is not rendering properly in new transaction screen (#336)
* Fixed bug [CORDA-282] - TX id is not rendering properly in the New Cash Transaction screen
2017-03-09 15:55:00 +00:00
Ross Nicoll
b5ba070301 Revert "Non-ssl artemis acceptor for RPC connection. (#271)"
This reverts commit f0d82e4918.
2017-03-06 14:03:23 +00:00
Ross Nicoll
0f6b806047 Add anonymous text in case party lookup fails 2017-03-02 12:07:12 +00:00
Patrick Kuo
dab80510f4 Fix not displaying Anonymous issuer name correctly in Explorer 2017-03-02 12:07:12 +00:00
Patrick Kuo
f0d82e4918 Non-ssl artemis acceptor for RPC connection. (#271)
* New non-ssl acceptor in artemis server for RPC connection.
2017-02-24 15:36:36 +00:00
Ross Nicoll
ed093cdb9d Enforce separation of Party and AnonymousParty 2017-02-16 11:50:33 +00:00
Ross Nicoll
71babc7019 Remove use of full parties from contract states 2017-02-15 11:43:13 +00:00
Ross Nicoll
98c30f6432 Remove CashFlow
Remove the CashFlow flow, replacing it with CashFlowCommand which can be used for the use-cases
with instructions passed around as an object.
2017-02-09 18:22:58 +00:00
Ross Nicoll
9055c9d9b0 Split CashFlow into three flows
Split CashFlow into independent CashIssueFlow, CashExitFlow and CashPaymentFlow,
so that users can be given access to one but not the other(s).

Signed-off-by: Ross Nicoll <ross.nicoll@r3.com>
2017-02-09 15:43:48 +00:00
Ross Nicoll
47d260625a Add AnonymousParty superclass of Party
Add AnonymousParty superclass of Party in preparation for anonymising parties stored in
contract states.

Signed-off-by: Ross Nicoll <ross.nicoll@r3.com>
2017-02-09 11:37:32 +00:00
Gary Rowe
b1c5de1112 Fix the port numbers in the documentation to match actual values 2017-02-06 16:22:15 +00:00
Shams Asari
b86c80691e FlowException serialised over RPC (subtypes are flattened), and improvement to startFlow RPC for correct exception handling 2017-02-03 11:21:10 +00:00
chalkido
087570e74d toStringWithSuffix decimal mark unit-test issue on non UK/US Locale (#209)
Make use of default Locale to temporarily bypass unit-testing of toStringWithSuffix failing due to different decimal marks on non anglo saxon Locales.
2017-02-02 18:06:48 +00:00