universa 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +18 -0
 - data/bin/umi/bin/umi +2 -2
 - data/bin/umi/bin/umi.bat +1 -1
 - data/lib/universa.rb +4 -0
 - data/lib/universa/contract.rb +20 -0
 - data/lib/universa/keys.rb +52 -0
 - data/lib/universa/service.rb +143 -0
 - data/lib/universa/tools.rb +8 -0
 - data/lib/universa/umi.rb +51 -12
 - data/lib/universa/version.rb +1 -1
 - metadata +6 -3
 - data/bin/umi/lib/com.icodici.umi-0.8.8.jar +0 -0
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 61a9637495cf67d3ac90b3447038b6b224646cd4f36a2db7619aae13274232af
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 2b6b963df5082f420ab80bf3bd47c509846ddb4d3085cc9eb19939e4c906c9ed
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 973eb722475a35230ce1c595faab7c47e730eb7573f737d113475d5cb4405f4d5fc6c1a3f02393e7e177e5a384d838acf53aa65641a5b5f76172ee42e60bc88b
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: a901518e1151a239f43f309512d1e9e8bf6f87e40a31f111b994c6f9086aad9e41cd31cb5fae7c6370d80309f6d37c6c522b7b14c347baaed12f5f09bcc56c49
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -29,6 +29,8 @@ Or install it yourself as: 
     | 
|
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
            ## Usage
         
     | 
| 
       31 
31 
     | 
    
         | 
| 
      
 32 
     | 
    
         
            +
            ### Direct access to UMI 
         
     | 
| 
      
 33 
     | 
    
         
            +
             
         
     | 
| 
       32 
34 
     | 
    
         
             
            So far, you can only get direct access the the Java API functions. To get it:
         
     | 
| 
       33 
35 
     | 
    
         | 
| 
       34 
36 
     | 
    
         
             
            ```ruby
         
     | 
| 
         @@ -55,6 +57,22 @@ for more information see: 
     | 
|
| 
       55 
57 
     | 
    
         
             
            - Universa UMI server: https://kb.universa.io/umi_protocol/98
         
     | 
| 
       56 
58 
     | 
    
         
             
            - Farcall [gem](https://github.com/sergeych/farcall) and [protocol](https://github.com/sergeych/farcall/wiki).
         
     | 
| 
       57 
59 
     | 
    
         | 
| 
      
 60 
     | 
    
         
            +
            ### Use UMI service (alfa state)
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
            The Universa::Service greatly simplify work taking all boilerplate. Just create objects almost as usual and use them
         
     | 
| 
      
 63 
     | 
    
         
            +
            as is they are local:
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 66 
     | 
    
         
            +
            key = PrivateKey,new(open('mykey.private.unikey', 'rb').read)
         
     | 
| 
      
 67 
     | 
    
         
            +
            contract = Contract.new(key)
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            contract.seal()
         
     | 
| 
      
 70 
     | 
    
         
            +
            p contract.check()
         
     | 
| 
      
 71 
     | 
    
         
            +
            ```
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            The system will create UMI server and do all the work for you. Look at the RemoteAdapter class to see how does it
         
     | 
| 
      
 74 
     | 
    
         
            +
            work. Soon we'll add adapters for all frequently used Universa classes.
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
       58 
76 
     | 
    
         
             
            ## Development
         
     | 
| 
       59 
77 
     | 
    
         | 
| 
       60 
78 
     | 
    
         
             
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         
     | 
    
        data/bin/umi/bin/umi
    CHANGED
    
    | 
         @@ -267,7 +267,7 @@ loadConfigFile() { 
     | 
|
| 
       267 
267 
     | 
    
         
             
            }
         
     | 
| 
       268 
268 
     | 
    
         | 
| 
       269 
269 
     | 
    
         
             
            # Now check to see if it's a good enough version
         
     | 
| 
       270 
     | 
    
         
            -
            # TODO - Check to see if we have a configured default java version, otherwise use 1. 
     | 
| 
      
 270 
     | 
    
         
            +
            # TODO - Check to see if we have a configured default java version, otherwise use 1.8
         
     | 
| 
       271 
271 
     | 
    
         
             
            java_version_check() {
         
     | 
| 
       272 
272 
     | 
    
         
             
              readonly java_version=$("$java_cmd" -version 2>&1 | awk -F '"' '/version/ {print $2}')
         
     | 
| 
       273 
273 
     | 
    
         
             
              if [[ "$java_version" == "" ]]; then
         
     | 
| 
         @@ -344,7 +344,7 @@ declare -r lib_dir="$(realpath "${app_home}/../lib")" 
     | 
|
| 
       344 
344 
     | 
    
         
             
            declare -a app_mainclass=(com.icodici.farcallscala.Main)
         
     | 
| 
       345 
345 
     | 
    
         | 
| 
       346 
346 
     | 
    
         
             
            declare -r script_conf_file="${app_home}/../conf/application.ini"
         
     | 
| 
       347 
     | 
    
         
            -
            declare -r app_classpath="$lib_dir/com.icodici.umi-0.8. 
     | 
| 
      
 347 
     | 
    
         
            +
            declare -r app_classpath="$lib_dir/com.icodici.umi-0.8.10.jar:$lib_dir/org.scala-lang.scala-library-2.12.7.jar:$lib_dir/com.icodici.universa_core-3.8.3.jar:$lib_dir/org.yaml.snakeyaml-1.18.jar:$lib_dir/net.sf.jopt-simple.jopt-simple-4.9.jar:$lib_dir/org.postgresql.postgresql-42.1.4.jar:$lib_dir/org.xerial.sqlite-jdbc-3.8.9.1.jar:$lib_dir/com.icodici.nanohttpd-2.1.0.jar:$lib_dir/com.icodici.common_tools-3.8.3.jar:$lib_dir/com.eclipsesource.minimal-json.minimal-json-0.9.4.jar:$lib_dir/net.java.dev.jna.jna-4.5.1.jar:$lib_dir/org.checkerframework.checker-qual-2.3.2.jar:$lib_dir/com.icodici.crypto-3.8.3.jar:$lib_dir/com.madgag.spongycastle.core-1.58.0.0.jar:$lib_dir/com.squareup.jnagmp.jnagmp-2.0.0.jar:$lib_dir/com.typesafe.play.play-json_2.12-2.6.10.jar:$lib_dir/com.typesafe.play.play-functional_2.12-2.6.10.jar:$lib_dir/org.scala-lang.scala-reflect-2.12.7.jar:$lib_dir/org.typelevel.macro-compat_2.12-1.1.1.jar:$lib_dir/joda-time.joda-time-2.9.9.jar:$lib_dir/com.fasterxml.jackson.core.jackson-core-2.8.11.jar:$lib_dir/com.fasterxml.jackson.core.jackson-annotations-2.8.11.jar:$lib_dir/com.fasterxml.jackson.datatype.jackson-datatype-jdk8-2.8.11.jar:$lib_dir/com.fasterxml.jackson.core.jackson-databind-2.8.11.1.jar:$lib_dir/com.fasterxml.jackson.datatype.jackson-datatype-jsr310-2.8.11.jar:$lib_dir/org.scala-sbt.ipcsocket.ipcsocket-1.0.0.jar:$lib_dir/net.java.dev.jna.jna-platform-4.5.0.jar"
         
     | 
| 
       348 
348 
     | 
    
         | 
| 
       349 
349 
     | 
    
         
             
            # java_cmd is overrode in process_args when -java-home is used
         
     | 
| 
       350 
350 
     | 
    
         
             
            declare java_cmd=$(get_java_cmd)
         
     | 
    
        data/bin/umi/bin/umi.bat
    CHANGED
    
    | 
         @@ -80,7 +80,7 @@ rem "-J" is stripped, "-D" is left as is, and everything is appended to JAVA_OPT 
     | 
|
| 
       80 
80 
     | 
    
         
             
            set _JAVA_PARAMS=
         
     | 
| 
       81 
81 
     | 
    
         
             
            set _APP_ARGS=
         
     | 
| 
       82 
82 
     | 
    
         | 
| 
       83 
     | 
    
         
            -
            set "APP_CLASSPATH=%APP_LIB_DIR%\com.icodici.umi-0.8. 
     | 
| 
      
 83 
     | 
    
         
            +
            set "APP_CLASSPATH=%APP_LIB_DIR%\com.icodici.umi-0.8.10.jar;%APP_LIB_DIR%\org.scala-lang.scala-library-2.12.7.jar;%APP_LIB_DIR%\com.icodici.universa_core-3.8.3.jar;%APP_LIB_DIR%\org.yaml.snakeyaml-1.18.jar;%APP_LIB_DIR%\net.sf.jopt-simple.jopt-simple-4.9.jar;%APP_LIB_DIR%\org.postgresql.postgresql-42.1.4.jar;%APP_LIB_DIR%\org.xerial.sqlite-jdbc-3.8.9.1.jar;%APP_LIB_DIR%\com.icodici.nanohttpd-2.1.0.jar;%APP_LIB_DIR%\com.icodici.common_tools-3.8.3.jar;%APP_LIB_DIR%\com.eclipsesource.minimal-json.minimal-json-0.9.4.jar;%APP_LIB_DIR%\net.java.dev.jna.jna-4.5.1.jar;%APP_LIB_DIR%\org.checkerframework.checker-qual-2.3.2.jar;%APP_LIB_DIR%\com.icodici.crypto-3.8.3.jar;%APP_LIB_DIR%\com.madgag.spongycastle.core-1.58.0.0.jar;%APP_LIB_DIR%\com.squareup.jnagmp.jnagmp-2.0.0.jar;%APP_LIB_DIR%\com.typesafe.play.play-json_2.12-2.6.10.jar;%APP_LIB_DIR%\com.typesafe.play.play-functional_2.12-2.6.10.jar;%APP_LIB_DIR%\org.scala-lang.scala-reflect-2.12.7.jar;%APP_LIB_DIR%\org.typelevel.macro-compat_2.12-1.1.1.jar;%APP_LIB_DIR%\joda-time.joda-time-2.9.9.jar;%APP_LIB_DIR%\com.fasterxml.jackson.core.jackson-core-2.8.11.jar;%APP_LIB_DIR%\com.fasterxml.jackson.core.jackson-annotations-2.8.11.jar;%APP_LIB_DIR%\com.fasterxml.jackson.datatype.jackson-datatype-jdk8-2.8.11.jar;%APP_LIB_DIR%\com.fasterxml.jackson.core.jackson-databind-2.8.11.1.jar;%APP_LIB_DIR%\com.fasterxml.jackson.datatype.jackson-datatype-jsr310-2.8.11.jar;%APP_LIB_DIR%\org.scala-sbt.ipcsocket.ipcsocket-1.0.0.jar;%APP_LIB_DIR%\net.java.dev.jna.jna-platform-4.5.0.jar"
         
     | 
| 
       84 
84 
     | 
    
         
             
            set "APP_MAIN_CLASS=com.icodici.farcallscala.Main"
         
     | 
| 
       85 
85 
     | 
    
         
             
            set "SCRIPT_CONF_FILE=%APP_HOME%\conf\application.ini"
         
     | 
| 
       86 
86 
     | 
    
         | 
    
        data/lib/universa.rb
    CHANGED
    
    
| 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Universa
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              # Universa contract adapter.
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Contract < RemoteAdapter
         
     | 
| 
      
 5 
     | 
    
         
            +
                remote_class "com.icodici.universa.contract.Contract"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                # seal the contract
         
     | 
| 
      
 8 
     | 
    
         
            +
                # @return [String] contract packed to the binary string
         
     | 
| 
      
 9 
     | 
    
         
            +
                def seal
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @proxy.seal()
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                # returns keys that will be used to sign this contract on next {seal}.
         
     | 
| 
      
 14 
     | 
    
         
            +
                # @return [Set<PrivateKey>] set of private keys
         
     | 
| 
      
 15 
     | 
    
         
            +
                def signing_keys
         
     | 
| 
      
 16 
     | 
    
         
            +
                  get_keys_to_sign_with
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,52 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Universa
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
              # A +com.icodici.crypto.PrivateKey+ extension. As the key is immutable,
         
     | 
| 
      
 4 
     | 
    
         
            +
              # caching is used to avoid innecessary UMI calls.
         
     | 
| 
      
 5 
     | 
    
         
            +
              class PrivateKey < RemoteAdapter
         
     | 
| 
      
 6 
     | 
    
         
            +
                remote_class 'com.icodici.crypto.PrivateKey'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                # @return [KeyAddress] short address of the corresponding public key
         
     | 
| 
      
 9 
     | 
    
         
            +
                def short_address
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @short_address ||= public_key.short_address
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                # @return [KeyAddress] long address of the corresponding public key
         
     | 
| 
      
 14 
     | 
    
         
            +
                def long_address
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @long_address ||= public_key.long_address
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                # @return [PublicKey] public key that matches this
         
     | 
| 
      
 19 
     | 
    
         
            +
                def public_key
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @public_key ||= get_public_key
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              # A +com.icodici.crypto.PublicKey+ extension. As the key is immutable,
         
     | 
| 
      
 25 
     | 
    
         
            +
              # caching is used to avoid innecessary UMI calls.
         
     | 
| 
      
 26 
     | 
    
         
            +
              class PublicKey < RemoteAdapter
         
     | 
| 
      
 27 
     | 
    
         
            +
                remote_class 'com.icodici.crypto.PublicKey'
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                # @return [KeyAddress] short address
         
     | 
| 
      
 30 
     | 
    
         
            +
                def short_address
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @short_address ||= get_short_address()
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                # @return [KeyAddress] long address
         
     | 
| 
      
 35 
     | 
    
         
            +
                def long_address
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @long_address ||= get_long_address()
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              # The +com.icodici.crypto.KeyAddress+ extension. As it is immutable, caching is
         
     | 
| 
      
 41 
     | 
    
         
            +
              # used to avoid unnecessary UMI calls.
         
     | 
| 
      
 42 
     | 
    
         
            +
              class KeyAddress < RemoteAdapter
         
     | 
| 
      
 43 
     | 
    
         
            +
                remote_class 'com.icodici.crypto.KeyAddress'
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                # String form of the key which could be used to unpack it back
         
     | 
| 
      
 46 
     | 
    
         
            +
                # @return [String] packed string representation
         
     | 
| 
      
 47 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 48 
     | 
    
         
            +
                  @string ||= toString()
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,143 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'singleton'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Universa
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              # The service is a singleton to provide porcess-wide objects and methods. For example,
         
     | 
| 
      
 6 
     | 
    
         
            +
              # the {UMI} interface and reference class factory are unique per-process for Universa
         
     | 
| 
      
 7 
     | 
    
         
            +
              # library. It uses exactly one lazy created {UMI} connection which is shared among all threads.
         
     | 
| 
      
 8 
     | 
    
         
            +
              # As UMI server is multithreaded by nature, is will not block ruby threads waiting for remote
         
     | 
| 
      
 9 
     | 
    
         
            +
              # invocation.
         
     | 
| 
      
 10 
     | 
    
         
            +
              class Service
         
     | 
| 
      
 11 
     | 
    
         
            +
                include Singleton
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                # Setup service initial parameters
         
     | 
| 
      
 14 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @config = SmartHash.new path: nil
         
     | 
| 
      
 16 
     | 
    
         
            +
                  @known_proxies = {}
         
     | 
| 
      
 17 
     | 
    
         
            +
                  [Contract, PrivateKey, PublicKey, KeyAddress].each {|klass| register_proxy klass}
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                # Implementation of {Service.configure}
         
     | 
| 
      
 21 
     | 
    
         
            +
                def configure &block
         
     | 
| 
      
 22 
     | 
    
         
            +
                  raise Error, "config call must happen before interface creation" if @umi
         
     | 
| 
      
 23 
     | 
    
         
            +
                  block.call @config
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                # Implementation of {Service.umi}
         
     | 
| 
      
 27 
     | 
    
         
            +
                def umi
         
     | 
| 
      
 28 
     | 
    
         
            +
                  c = @config.to_h.transform_keys(&:to_sym).update(convert_case: true)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  c[:factory] = -> (ref) {create_proxy(ref)}
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @umi ||= UMI.new(c.delete(:path), **c)
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                # push string to service log
         
     | 
| 
      
 35 
     | 
    
         
            +
                def log msg
         
     | 
| 
      
 36 
     | 
    
         
            +
                  puts "U:Service: #{msg}"
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                # Create objectproxy for known types
         
     | 
| 
      
 40 
     | 
    
         
            +
                # @param [Ref] ref to transform
         
     | 
| 
      
 41 
     | 
    
         
            +
                # @return [RemoteAdapter | Ref] transformed or source reference
         
     | 
| 
      
 42 
     | 
    
         
            +
                def create_proxy ref
         
     | 
| 
      
 43 
     | 
    
         
            +
                  proxy_class = @known_proxies[ref._remote_class_name]
         
     | 
| 
      
 44 
     | 
    
         
            +
                  return ref unless proxy_class
         
     | 
| 
      
 45 
     | 
    
         
            +
                  proxy_class.new(ReferenceCreationData.new(ref))
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  # Call it before everything to update UMI interface parameters before is is created.
         
     | 
| 
      
 51 
     | 
    
         
            +
                  # Calling it when UMI is already constructed raises Error.
         
     | 
| 
      
 52 
     | 
    
         
            +
                  def configure &block
         
     | 
| 
      
 53 
     | 
    
         
            +
                    instance.configure &block
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  # Get the global UMI interface, creating it if need.
         
     | 
| 
      
 57 
     | 
    
         
            +
                  # @return [UMI] ready interface
         
     | 
| 
      
 58 
     | 
    
         
            +
                  def umi
         
     | 
| 
      
 59 
     | 
    
         
            +
                    instance.umi
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                private
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                def register_proxy klass
         
     | 
| 
      
 66 
     | 
    
         
            +
                  remote_class_name = klass.remote_class_name
         
     | 
| 
      
 67 
     | 
    
         
            +
                  raise Error, "#{remote_class_name} is already registered in Service" if @known_proxies.include?(remote_class_name)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  @known_proxies[remote_class_name] = klass
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
              # The basic class to write remote class adapters (extensions). Delegates contained {Ref} instance therefore behaves
         
     | 
| 
      
 73 
     | 
    
         
            +
              # like remote interface with some extensions.
         
     | 
| 
      
 74 
     | 
    
         
            +
              #
         
     | 
| 
      
 75 
     | 
    
         
            +
              # Key feature of RemoteAdapter class is the cross-call persistence. It means once created instances of the
         
     | 
| 
      
 76 
     | 
    
         
            +
              # RemoteAdapter descendants are cached just like (in fact, instead of) {Ref} instances, so  when the remote party
         
     | 
| 
      
 77 
     | 
    
         
            +
              # returns the reference to the object once wrapped by this instance, the instance will be returned unless it is
         
     | 
| 
      
 78 
     | 
    
         
            +
              # already garbage collected. instance will be returned, what means sort of cross-platform calls persistence.
         
     | 
| 
      
 79 
     | 
    
         
            +
              #
         
     | 
| 
      
 80 
     | 
    
         
            +
              # Extending this class normally should not implement the constructor, By defaul the constructor is passed to
         
     | 
| 
      
 81 
     | 
    
         
            +
              # the remote to create remote instance.
         
     | 
| 
      
 82 
     | 
    
         
            +
              class RemoteAdapter < Delegator
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                # Instantiate new proxy object passing arguments to the remote constructor. The UMO host will try
         
     | 
| 
      
 85 
     | 
    
         
            +
                # ot find overloaded constructor that matches the arguments.
         
     | 
| 
      
 86 
     | 
    
         
            +
                #
         
     | 
| 
      
 87 
     | 
    
         
            +
                # @param [*Any] args any arguments that remote constructor may accept.
         
     | 
| 
      
 88 
     | 
    
         
            +
                def initialize(*args)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  if args.length == 1 && args[0].is_a?(ReferenceCreationData)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    @remote = args[0].ref
         
     | 
| 
      
 91 
     | 
    
         
            +
                  else
         
     | 
| 
      
 92 
     | 
    
         
            +
                    # User called constructor
         
     | 
| 
      
 93 
     | 
    
         
            +
                    remote_class_name = self.class.remote_class_name
         
     | 
| 
      
 94 
     | 
    
         
            +
                    remote_class_name&.length or raise Error, "provide remote_class_name"
         
     | 
| 
      
 95 
     | 
    
         
            +
                    @remote = Service.umi.instantiate remote_class_name.split('.')[-1], *args, adapter: self
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                # Delegated object
         
     | 
| 
      
 100 
     | 
    
         
            +
                # @return [Ref] the wrapped instance whose methpds are delegated by this
         
     | 
| 
      
 101 
     | 
    
         
            +
                def __getobj__
         
     | 
| 
      
 102 
     | 
    
         
            +
                  @remote
         
     | 
| 
      
 103 
     | 
    
         
            +
                end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                # Updating proxied object is not allowed. Raises error.
         
     | 
| 
      
 106 
     | 
    
         
            +
                def __setobj__
         
     | 
| 
      
 107 
     | 
    
         
            +
                  raise "ObectProxy does not support changing referenced object"
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                # Returns remote class name. There is no need to override it, when inheriting it use +remote_class+ helper:
         
     | 
| 
      
 111 
     | 
    
         
            +
                #
         
     | 
| 
      
 112 
     | 
    
         
            +
                #   class MyKeyAddress < ObjectProxy
         
     | 
| 
      
 113 
     | 
    
         
            +
                #      remote_class 'com.icodici.crypto.KeyAddress'
         
     | 
| 
      
 114 
     | 
    
         
            +
                #
         
     | 
| 
      
 115 
     | 
    
         
            +
                #      #...
         
     | 
| 
      
 116 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 117 
     | 
    
         
            +
                #
         
     | 
| 
      
 118 
     | 
    
         
            +
                # Notice: remote_class will do allnecessary work for you.
         
     | 
| 
      
 119 
     | 
    
         
            +
                #
         
     | 
| 
      
 120 
     | 
    
         
            +
                # @return [String] remote class name
         
     | 
| 
      
 121 
     | 
    
         
            +
                def self.remote_class_name
         
     | 
| 
      
 122 
     | 
    
         
            +
                  raise Error, "provde remote class name"
         
     | 
| 
      
 123 
     | 
    
         
            +
                end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                # Registers remote class name to be used with this adapted. Call it early in descendant class
         
     | 
| 
      
 126 
     | 
    
         
            +
                # declaration.
         
     | 
| 
      
 127 
     | 
    
         
            +
                def self.remote_class name
         
     | 
| 
      
 128 
     | 
    
         
            +
                  class_eval "def self.remote_class_name; '#{name}'; end"
         
     | 
| 
      
 129 
     | 
    
         
            +
                end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                # debugging label
         
     | 
| 
      
 132 
     | 
    
         
            +
                def inspect
         
     | 
| 
      
 133 
     | 
    
         
            +
                  "<#{self.class.name}:#{__id__}:#{@remote._remote_class_name}:#{@remote._remote_id}}>"
         
     | 
| 
      
 134 
     | 
    
         
            +
                end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                # call the remote toString(). Does not cache it.
         
     | 
| 
      
 137 
     | 
    
         
            +
                # @return [String]
         
     | 
| 
      
 138 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 139 
     | 
    
         
            +
                  toString()
         
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
              end
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/universa/umi.rb
    CHANGED
    
    | 
         @@ -64,7 +64,7 @@ module Universa 
     | 
|
| 
       64 
64 
     | 
    
         
             
                # @param [String] system expected on the remote side. 'UMI' us a universa umi server.
         
     | 
| 
       65 
65 
     | 
    
         
             
                # @param [Boolean] convert_case it true, convert ruby style snake case `get_some_stuff()` to java style lower camel
         
     | 
| 
       66 
66 
     | 
    
         
             
                #                  case `getSomeStuff()` while calling methods. Does not affect class names on {instantiate}.
         
     | 
| 
       67 
     | 
    
         
            -
                def initialize(path = nil, version_check: /./, system: "UMI", log: 'sessionlog.txt', convert_case: true)
         
     | 
| 
      
 67 
     | 
    
         
            +
                def initialize(path = nil, version_check: /./, system: "UMI", log: 'sessionlog.txt', convert_case: true, factory: nil)
         
     | 
| 
       68 
68 
     | 
    
         
             
                  path ||= File.expand_path(File.split(__FILE__)[0] + "/../../bin/umi/bin/umi")
         
     | 
| 
       69 
69 
     | 
    
         
             
                  @in, @out, @err, @wtr = Open3.popen3("#{path} #{log ? "-log #{log}" : ''}")
         
     | 
| 
       70 
70 
     | 
    
         
             
                  @endpoint = Farcall::Endpoint.new(
         
     | 
| 
         @@ -73,7 +73,7 @@ module Universa 
     | 
|
| 
       73 
73 
     | 
    
         
             
                  @lock = Monitor.new
         
     | 
| 
       74 
74 
     | 
    
         
             
                  @cache = {}
         
     | 
| 
       75 
75 
     | 
    
         
             
                  @closed = false
         
     | 
| 
       76 
     | 
    
         
            -
                  @convert_case = convert_case
         
     | 
| 
      
 76 
     | 
    
         
            +
                  @convert_case, @factory = convert_case, factory
         
     | 
| 
       77 
77 
     | 
    
         
             
                  @references = {}
         
     | 
| 
       78 
78 
     | 
    
         
             
                  start_cleanup_queue
         
     | 
| 
       79 
79 
     | 
    
         
             
                  @version = call("version")
         
     | 
| 
         @@ -95,9 +95,9 @@ module Universa 
     | 
|
| 
       95 
95 
     | 
    
         
             
                # housekeeping required, like memory leaks prevention and direct method calling.
         
     | 
| 
       96 
96 
     | 
    
         
             
                #
         
     | 
| 
       97 
97 
     | 
    
         
             
                # @return [Ref] reference to the remotely created object. See {Ref}.
         
     | 
| 
       98 
     | 
    
         
            -
                def instantiate(object_class_name, *args)
         
     | 
| 
      
 98 
     | 
    
         
            +
                def instantiate(object_class_name, *args, adapter: nil)
         
     | 
| 
       99 
99 
     | 
    
         
             
                  ensure_open
         
     | 
| 
       100 
     | 
    
         
            -
                  create_reference call("instantiate", object_class_name, *prepare_args(args))
         
     | 
| 
      
 100 
     | 
    
         
            +
                  create_reference call("instantiate", object_class_name, *prepare_args(args)), adapter
         
     | 
| 
       101 
101 
     | 
    
         
             
                end
         
     | 
| 
       102 
102 
     | 
    
         | 
| 
       103 
103 
     | 
    
         
             
                # Invoke method by name. Should not be used directly; use {Ref} instance to call its methods.
         
     | 
| 
         @@ -163,8 +163,9 @@ module Universa 
     | 
|
| 
       163 
163 
     | 
    
         | 
| 
       164 
164 
     | 
    
         
             
                # Create a reference correcting adapting remote types to ruby ecosystem, for example loads
         
     | 
| 
       165 
165 
     | 
    
         
             
                # remote Java Set to a local ruby Set.
         
     | 
| 
       166 
     | 
    
         
            -
                def create_reference  
     | 
| 
       167 
     | 
    
         
            -
                  r = build_reference reference_record
         
     | 
| 
      
 166 
     | 
    
         
            +
                def create_reference(reference_record, adapter = nil)
         
     | 
| 
      
 167 
     | 
    
         
            +
                  r = build_reference reference_record, adapter
         
     | 
| 
      
 168 
     | 
    
         
            +
                  return r if adapter
         
     | 
| 
       168 
169 
     | 
    
         
             
                  case reference_record.className
         
     | 
| 
       169 
170 
     | 
    
         
             
                    when 'java.util.HashSet'
         
     | 
| 
       170 
171 
     | 
    
         
             
                      r.toArray()
         
     | 
| 
         @@ -175,16 +176,31 @@ module Universa 
     | 
|
| 
       175 
176 
     | 
    
         | 
| 
       176 
177 
     | 
    
         
             
                # Create a reference from UMI remote object reference structure. Returns existing object if any. Takes care
         
     | 
| 
       177 
178 
     | 
    
         
             
                # of dropping remote object when ruby object gets collected.
         
     | 
| 
       178 
     | 
    
         
            -
                def build_reference  
     | 
| 
      
 179 
     | 
    
         
            +
                def build_reference(reference_record, proxy)
         
     | 
| 
       179 
180 
     | 
    
         
             
                  @lock.synchronize {
         
     | 
| 
       180 
181 
     | 
    
         
             
                    remote_id = reference_record.id
         
     | 
| 
       181 
182 
     | 
    
         
             
                    ref = @cache[remote_id]&.get
         
     | 
| 
       182 
183 
     | 
    
         
             
                    if !ref
         
     | 
| 
       183 
184 
     | 
    
         
             
                      # log "Creating new reference to remote #{remote_id}"
         
     | 
| 
       184 
185 
     | 
    
         
             
                      ref = Ref.new(self, reference_record)
         
     | 
| 
       185 
     | 
    
         
            -
                       
     | 
| 
       186 
     | 
    
         
            -
                       
     | 
| 
      
 186 
     | 
    
         
            +
                      # IF we provide proxy that will consume the ref, we'll cache the proxy object,
         
     | 
| 
      
 187 
     | 
    
         
            +
                      # otherwise we run factory and cahce whatever it returns or the ref itself
         
     | 
| 
      
 188 
     | 
    
         
            +
                      obj = if proxy
         
     | 
| 
      
 189 
     | 
    
         
            +
                              # Proxy object will delegate the ref we return from there
         
     | 
| 
      
 190 
     | 
    
         
            +
                              # no action need
         
     | 
| 
      
 191 
     | 
    
         
            +
                              proxy
         
     | 
| 
      
 192 
     | 
    
         
            +
                            else
         
     | 
| 
      
 193 
     | 
    
         
            +
                              # new object: factory may create proxy for us and we'll cache it for later
         
     | 
| 
      
 194 
     | 
    
         
            +
                              # use:
         
     | 
| 
      
 195 
     | 
    
         
            +
                              @factory and ref = @factory.call(ref)
         
     | 
| 
      
 196 
     | 
    
         
            +
                              ref
         
     | 
| 
      
 197 
     | 
    
         
            +
                            end
         
     | 
| 
      
 198 
     | 
    
         
            +
                      # Important: we set finalizer fot the target object
         
     | 
| 
      
 199 
     | 
    
         
            +
                      ObjectSpace.define_finalizer(obj, create_finalizer(remote_id))
         
     | 
| 
      
 200 
     | 
    
         
            +
                      # and we cache target object
         
     | 
| 
      
 201 
     | 
    
         
            +
                      @cache[remote_id] = WeakReference.new(obj)
         
     | 
| 
       187 
202 
     | 
    
         
             
                    end
         
     | 
| 
      
 203 
     | 
    
         
            +
                    # but we return reference: it the proxy constructor calls us, it'll need the ref:
         
     | 
| 
       188 
204 
     | 
    
         
             
                    ref
         
     | 
| 
       189 
205 
     | 
    
         
             
                  }
         
     | 
| 
       190 
206 
     | 
    
         
             
                end
         
     | 
| 
         @@ -334,9 +350,14 @@ module Universa 
     | 
|
| 
       334 
350 
     | 
    
         
             
                  @id
         
     | 
| 
       335 
351 
     | 
    
         
             
                end
         
     | 
| 
       336 
352 
     | 
    
         | 
| 
      
 353 
     | 
    
         
            +
                # name of the remote class (provided by remote)
         
     | 
| 
      
 354 
     | 
    
         
            +
                def _remote_class_name
         
     | 
| 
      
 355 
     | 
    
         
            +
                  @ref.className
         
     | 
| 
      
 356 
     | 
    
         
            +
                end
         
     | 
| 
      
 357 
     | 
    
         
            +
             
     | 
| 
       337 
358 
     | 
    
         
             
                # Internal use only. Allow processing remote commands as local calls
         
     | 
| 
       338 
359 
     | 
    
         
             
                def respond_to_missing?(method_name, include_private = false)
         
     | 
| 
       339 
     | 
    
         
            -
                  method_name[0] == '_' ? super : true
         
     | 
| 
      
 360 
     | 
    
         
            +
                  method_name[0] == '_' || LOCAL_METHODS.include?(method_name) ? super : true
         
     | 
| 
       340 
361 
     | 
    
         
             
                end
         
     | 
| 
       341 
362 
     | 
    
         | 
| 
       342 
363 
     | 
    
         
             
                #Internal use only. Call remote method as needed. This is where all the magick comes from: it call remote method instead of the
         
     | 
| 
         @@ -357,13 +378,13 @@ module Universa 
     | 
|
| 
       357 
378 
     | 
    
         | 
| 
       358 
379 
     | 
    
         
             
                # short data label for instance
         
     | 
| 
       359 
380 
     | 
    
         
             
                def inspect
         
     | 
| 
       360 
     | 
    
         
            -
                  "<UMI:Ref:#{@umi.__id__}:#{@ref.className}:#{@id} 
     | 
| 
      
 381 
     | 
    
         
            +
                  "<UMI:Ref:#{@umi.__id__}:#{@ref.className}:#{@id}>"
         
     | 
| 
       361 
382 
     | 
    
         
             
                end
         
     | 
| 
       362 
383 
     | 
    
         | 
| 
       363 
384 
     | 
    
         
             
                # Checks that references are euqal: either both point to the same remote object or respective remote objects
         
     | 
| 
       364 
385 
     | 
    
         
             
                # are reported equals by the remote +equals()+ call.
         
     | 
| 
       365 
386 
     | 
    
         
             
                def ==(other)
         
     | 
| 
       366 
     | 
    
         
            -
                  other.is_a?(Ref) && other._umi == @umi &&
         
     | 
| 
      
 387 
     | 
    
         
            +
                  (other.is_a?(Ref) || other.is_a?(RemoteAdapter)) && other._umi == @umi &&
         
     | 
| 
       367 
388 
     | 
    
         
             
                      (other._remote_id == @id || other.equals(self))
         
     | 
| 
       368 
389 
     | 
    
         
             
                end
         
     | 
| 
       369 
390 
     | 
    
         | 
| 
         @@ -373,6 +394,24 @@ module Universa 
     | 
|
| 
       373 
394 
     | 
    
         
             
                  other.is_a?(Ref) && other._umi == @umi && other._remote_id == @id
         
     | 
| 
       374 
395 
     | 
    
         
             
                end
         
     | 
| 
       375 
396 
     | 
    
         | 
| 
      
 397 
     | 
    
         
            +
                private
         
     | 
| 
      
 398 
     | 
    
         
            +
             
     | 
| 
      
 399 
     | 
    
         
            +
                LOCAL_METHODS = Set.new(%i[i_respond_to_everything_so_im_not_really_a_matcher to_hash to_ary description])
         
     | 
| 
      
 400 
     | 
    
         
            +
              end
         
     | 
| 
      
 401 
     | 
    
         
            +
             
     | 
| 
      
 402 
     | 
    
         
            +
              # Service uses this class to contruct {RemoteAdapter} pointing to the existing remote object instead
         
     | 
| 
      
 403 
     | 
    
         
            +
              # of instantiating new one.
         
     | 
| 
      
 404 
     | 
    
         
            +
              #
         
     | 
| 
      
 405 
     | 
    
         
            +
              class ReferenceCreationData
         
     | 
| 
      
 406 
     | 
    
         
            +
                # reference to create proxy for
         
     | 
| 
      
 407 
     | 
    
         
            +
                # @return [Ref]
         
     | 
| 
      
 408 
     | 
    
         
            +
                attr :ref
         
     | 
| 
      
 409 
     | 
    
         
            +
             
     | 
| 
      
 410 
     | 
    
         
            +
                # we need to wrap this ref
         
     | 
| 
      
 411 
     | 
    
         
            +
                # @param [Ref] ref to wrap in {RemoteAdapter}
         
     | 
| 
      
 412 
     | 
    
         
            +
                def initialize ref
         
     | 
| 
      
 413 
     | 
    
         
            +
                  @ref = ref
         
     | 
| 
      
 414 
     | 
    
         
            +
                end
         
     | 
| 
       376 
415 
     | 
    
         
             
              end
         
     | 
| 
       377 
416 
     | 
    
         | 
| 
       378 
417 
     | 
    
         
             
            end
         
     | 
    
        data/lib/universa/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: universa
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.3
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - sergeych
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: exe
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2018-11- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2018-11-03 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: farcall
         
     | 
| 
         @@ -95,7 +95,6 @@ files: 
     | 
|
| 
       95 
95 
     | 
    
         
             
            - bin/umi/lib/com.icodici.common_tools-3.8.3.jar
         
     | 
| 
       96 
96 
     | 
    
         
             
            - bin/umi/lib/com.icodici.crypto-3.8.3.jar
         
     | 
| 
       97 
97 
     | 
    
         
             
            - bin/umi/lib/com.icodici.nanohttpd-2.1.0.jar
         
     | 
| 
       98 
     | 
    
         
            -
            - bin/umi/lib/com.icodici.umi-0.8.8.jar
         
     | 
| 
       99 
98 
     | 
    
         
             
            - bin/umi/lib/com.icodici.universa_core-3.8.3.jar
         
     | 
| 
       100 
99 
     | 
    
         
             
            - bin/umi/lib/com.madgag.spongycastle.core-1.58.0.0.jar
         
     | 
| 
       101 
100 
     | 
    
         
             
            - bin/umi/lib/com.squareup.jnagmp.jnagmp-2.0.0.jar
         
     | 
| 
         @@ -111,8 +110,12 @@ files: 
     | 
|
| 
       111 
110 
     | 
    
         
             
            - bin/umi/lib/org.yaml.snakeyaml-1.18.jar
         
     | 
| 
       112 
111 
     | 
    
         
             
            - exe/universa
         
     | 
| 
       113 
112 
     | 
    
         
             
            - lib/universa.rb
         
     | 
| 
      
 113 
     | 
    
         
            +
            - lib/universa/contract.rb
         
     | 
| 
       114 
114 
     | 
    
         
             
            - lib/universa/errors.rb
         
     | 
| 
      
 115 
     | 
    
         
            +
            - lib/universa/keys.rb
         
     | 
| 
      
 116 
     | 
    
         
            +
            - lib/universa/service.rb
         
     | 
| 
       115 
117 
     | 
    
         
             
            - lib/universa/string_utils.rb
         
     | 
| 
      
 118 
     | 
    
         
            +
            - lib/universa/tools.rb
         
     | 
| 
       116 
119 
     | 
    
         
             
            - lib/universa/umi.rb
         
     | 
| 
       117 
120 
     | 
    
         
             
            - lib/universa/version.rb
         
     | 
| 
       118 
121 
     | 
    
         
             
            - lib/universa/weak_reference.rb
         
     | 
| 
         Binary file 
     |