text:
1.2.12
======

Features and Improvements for LeoFS
-----------------------------------

* Able to use ``compact-suspend`` comamnd when the auto-compaction is enabled

Bugs Fixed
-----------

* [#390](https://github.com/leo-project/leofs/issues/390) ``leo_object_storage`` Unexpected 500 error when getting a zero size object not cached
* [#393](https://github.com/leo-project/leofs/issues/393) ``leo_object_storage`` Compaction can be slow because of the watchdog communication
* [#395](https://github.com/leo-project/leofs/issues/395) ``leo_gateway`` ``s3tests.functional.test_s3:test_bucket_list_maxkeys_zero`` failed
* [#396](https://github.com/leo-project/leofs/issues/396) ``leo_storage`` Auto Compaction tend to be executed on the same node
* [#398](https://github.com/leo-project/leofs/issues/398) ``leo_object_storage`` Compaction may stop unintentionally under heavy load

Used Libraries
---------------

* leo project
    * [leo_backend-db v1.1.9](https://github.com/leo-project/leo_backend_db/releases/tag/1.1.9)
    * [leo_cache v0.6.5](https://github.com/leo-project/leo_cache/releases/tag/0.6.5)
    * [leo_commons v1.1.2](https://github.com/leo-project/leo_commons/releases/tag/1.1.2)
    * [leo_dcerl v0.4.0](https://github.com/leo-project/leo_dcerl/releases/tag/0.4.0)
    * [leo_logger v1.1.6](https://github.com/leo-project/leo_logger/releases/tag/1.1.6)
    * [leo_mcerl v0.6.0](https://github.com/leo-project/leo_mcerl/releases/tag/0.6.0)
    * [leo_mq v1.3.11](https://github.com/leo-project/leo_mq/releases/tag/1.3.11)
    * [leo_object_storage v1.2.9](https://github.com/leo-project/leo_object_storage/releases/tag/1.2.9)
    * [leo_ordning_reda v1.1.0](https://github.com/leo-project/leo_ordning_reda/releases/tag/1.1.0)
    * [leo_redundant_manager 1.9.15](https://github.com/leo-project/leo_redundant_manager/releases/tag/1.9.15)
    * [leo_rpc v0.10.2](https://github.com/leo-project/leo_rpc/releases/tag/0.10.2)
    * [leo_pod v0.6.4](https://github.com/leo-project/leo_pod/releases/tag/0.6.4)
    * [leo_s3_libs v1.1.8](https://github.com/leo-project/leo_s3_libs/releases/tag/1.1.8)
    * [leo_statistics v1.1.6](https://github.com/leo-project/leo_statistics/releases/tag/1.1.6)
    * [leo_watchdog v0.10.2](https://github.com/leo-project/leo_watchdog/releases/tag/0.10.2)
    * [savanna_agent v0.4.9](https://github.com/leo-project/savanna_agent/releases/tag/0.4.9)
    * [savanna_commons v0.8.12](https://github.com/leo-project/savanna_commons/releases/tag/0.8.12)
    * [erpcgen v0.2.3](https://github.com/leo-project/erpcgen/releases/tag/0.2.3)
    * [nfs_rpc_server v0.2.3](https://github.com/leo-project/nfs_rpc_server/releases/tag/0.2.3)
    * [leo_gateway v1.2.12](https://github.com/leo-project/leo_gateway/releases/tag/1.2.12)
    * [leo_manager v1.2.12](https://github.com/leo-project/leo_manager/releases/tag/1.2.12)
    * [leo_storage v1.2.12](https://github.com/leo-project/leo_storage/releases/tag/1.2.12)
* others
    * [bitcask v2.0.0](https://github.com/lbasho/bitcask/releases/tag/2.0.0)
    * [cowboy v1.0.1](https://github.com/leo-project/cowboy/releases/tag/for-leofs-1.2.11)
    * [cowlib v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [elarm v0.3.0](https://github.com/leo-project/elarm/releases/tag/0.3.0)
    * [eleveldb v2.1.1](https://github.com/basho/eleveldb/releases/tag/2.1.1)
    * [folsom v0.8.2-for-leofs](https://github.com/leo-project/folsom/releases/tag/0.8.2-for-leofs)
    * [jiffy v0.13.3](https://github.com/davisp/jiffy/releases/tag/0.13.3)
    * [lz4 v0.2.2](https://github.com/leo-project/erlang-lz4/releases/tag/0.2.2)
    * [recon v0.8.5](https://github.com/ferd/recon/releases/tag/2.2.1)

1.2.11
======

Features and Improvements for LeoFS
-----------------------------------

*  [#377](https://github.com/leo-project/leofs/issues/377) ``leo_gateway`` Support logging bucket operation
*  ``leofs-adm`` Added ``diagnose-start`` command

Bugs Fixed
-----------

*  Retrieves range of an object
    *  [#376](https://github.com/leo-project/leofs/issues/376) ``leo_gateway`` Could not get an object with range
    *  [#382](https://github.com/leo-project/leofs/issues/382) ``leo_storage`` Incorrect handling of range get the first byte
* Leo Storage
    *  [#365](https://github.com/leo-project/leofs/issues/365) ``leo_storage`` ``auto-compaction`` Each storage node's data-compaction happened at almost same time
    *  [#378](https://github.com/leo-project/leofs/issues/378) ``leo_object_storage`` file:pread/3 could return {ok, Data} which size less than the number argument
    *  [#379](https://github.com/leo-project/leofs/issues/379) ``leo_storage`` ``leo_mq`` Decreased a performance of read and write operation during rebalance/recover-node
    *  [#383](https://github.com/leo-project/leofs/issues/383) ``leo_object_storage`` The result of du could be wrong
    *  [#385](https://github.com/leo-project/leofs/issues/385) ``leo_object_storage`` Found incorrect some data-blocks during the data-compaction
    *  [#387](https://github.com/leo-project/leofs/issues/387) ``leo_ordning_reda`` Close-operation should be executed when unexpected terminating
    *  Revised [leo_storage's configuration](https://github.com/leo-project/leo_storage/blob/master/priv/leo_storage.conf):
        *  Removed configurations to reduce administration costs and ``leo_storage`` calcurates each min-value and step-value
            *  compaction.waiting_time_min
            *  compaction.waiting_time_step
            *  compaction.batch_procs_min
            *  compaction.batch_procs_step
            *  mq.num_of_batch_process_min
            *  mq.num_of_batch_process_step
            *  mq.interval_between_batch_procs_min
            *  mq.interval_between_batch_procs_step
* Leo Gateway
    *  [#171](https://github.com/leo-project/leofs/issues/171) ``leo_gateway`` PHP client's headObject was not working
    *  [#384](https://github.com/leo-project/leofs/issues/384) ``leo_gateway`` Some access logs have been not recorded
* Leo Manager
    *  [#371](https://github.com/leo-project/leofs/issues/371) ``leo_manager`` ``leo_statistics`` Could NOT migrate from v1.0.x to 1.2

Used Libraries
---------------

* leo project
    * [leo_backend-db v1.1.9](https://github.com/leo-project/leo_backend_db/releases/tag/1.1.9)
    * [leo_cache v0.6.5](https://github.com/leo-project/leo_cache/releases/tag/0.6.5)
    * [leo_commons v1.1.2](https://github.com/leo-project/leo_commons/releases/tag/1.1.2)
    * [leo_dcerl v0.4.0](https://github.com/leo-project/leo_dcerl/releases/tag/0.4.0)
    * [leo_logger v1.1.6](https://github.com/leo-project/leo_logger/releases/tag/1.1.6)
    * [leo_mcerl v0.6.0](https://github.com/leo-project/leo_mcerl/releases/tag/0.6.0)
    * [leo_mq v1.3.11](https://github.com/leo-project/leo_mq/releases/tag/1.3.11)
    * [leo_object_storage v1.2.8](https://github.com/leo-project/leo_object_storage/releases/tag/1.2.8)
    * [leo_ordning_reda v1.1.0](https://github.com/leo-project/leo_ordning_reda/releases/tag/1.1.0)
    * [leo_redundant_manager 1.9.15](https://github.com/leo-project/leo_redundant_manager/releases/tag/1.9.15)
    * [leo_rpc v0.10.2](https://github.com/leo-project/leo_rpc/releases/tag/0.10.2)
    * [leo_pod v0.6.4](https://github.com/leo-project/leo_pod/releases/tag/0.6.4)
    * [leo_s3_libs v1.1.8](https://github.com/leo-project/leo_s3_libs/releases/tag/1.1.8)
    * [leo_statistics v1.1.6](https://github.com/leo-project/leo_statistics/releases/tag/1.1.6)
    * [leo_watchdog v0.10.1](https://github.com/leo-project/leo_watchdog/releases/tag/0.10.1)
    * [savanna_agent v0.4.9](https://github.com/leo-project/savanna_agent/releases/tag/0.4.9)
    * [savanna_commons v0.8.12](https://github.com/leo-project/savanna_commons/releases/tag/0.8.12)
    * [erpcgen v0.2.3](https://github.com/leo-project/erpcgen/releases/tag/0.2.3)
    * [nfs_rpc_server v0.2.3](https://github.com/leo-project/nfs_rpc_server/releases/tag/0.2.3)
    * [leo_gateway v1.2.11](https://github.com/leo-project/leo_gateway/releases/tag/1.2.11)
    * [leo_manager v1.2.11](https://github.com/leo-project/leo_manager/releases/tag/1.2.11)
    * [leo_storage v1.2.11](https://github.com/leo-project/leo_storage/releases/tag/1.2.11)
* others
    * [bitcask v2.0.0](https://github.com/lbasho/bitcask/releases/tag/2.0.0)
    * [cowboy v1.0.0](https://github.com/leo-project/cowboy/releases/tag/1.0.0)
    * [cowlib v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [elarm v0.3.0](https://github.com/leo-project/elarm/releases/tag/0.3.0)
    * [eleveldb v2.1.1](https://github.com/basho/eleveldb/releases/tag/2.1.1)
    * [folsom v0.8.2-for-leofs](https://github.com/leo-project/folsom/releases/tag/0.8.2-for-leofs)
    * [jiffy v0.13.3](https://github.com/davisp/jiffy/releases/tag/0.13.3)
    * [lz4 v0.2.2](https://github.com/leo-project/erlang-lz4/releases/tag/0.2.2)
    * [recon v0.8.5](https://github.com/ferd/recon/releases/tag/2.2.1)

1.2.10
======

Bugs Fixed
-----------

* [#366](https://github.com/leo-project/leofs/issues/366) ``leo_storage`` Cannot migrate old one to LeoFS v1.2.9
    * We're planning to implement and provide the auto-migration-test tool
* ``leo_statistics`` Strictly check creating mnesia's tables

Used Libraries
---------------

* leo project
    * [leo_backend-db v1.1.8](https://github.com/leo-project/leo_backend_db/releases/tag/1.1.8)
    * [leo_cache v0.6.3](https://github.com/leo-project/leo_cache/releases/tag/0.6.3)
    * [leo_commons v1.1.1](https://github.com/leo-project/leo_commons/releases/tag/1.1.1)
    * [leo_dcerl v0.2.12](https://github.com/leo-project/leo_dcerl/releases/tag/0.2.12)
    * [leo_logger v1.1.5](https://github.com/leo-project/leo_logger/releases/tag/1.1.5)
    * [leo_mcerl v0.4.1](https://github.com/leo-project/leo_mcerl/releases/tag/0.4.1)
    * [leo_mq v1.3.9](https://github.com/leo-project/leo_mq/releases/tag/1.3.9)
    * [leo_object_storage v1.2.7](https://github.com/leo-project/leo_object_storage/releases/tag/1.2.7)
    * [leo_ordning_reda v1.0.0](https://github.com/leo-project/leo_ordning_reda/releases/tag/1.0.0)
    * [leo_redundant_manager 1.9.13](https://github.com/leo-project/leo_redundant_manager/releases/tag/1.9.13)
    * [leo_rpc v0.10.1](https://github.com/leo-project/leo_rpc/releases/tag/0.10.1)
    * [leo_pod v0.6.3](https://github.com/leo-project/leo_pod/releases/tag/0.6.3)
    * [leo_s3_libs v1.1.7](https://github.com/leo-project/leo_s3_libs/releases/tag/1.1.7)
    * [leo_statistics v1.1.4](https://github.com/leo-project/leo_statistics/releases/tag/1.1.4)
    * [leo_watchdog v0.8.0](https://github.com/leo-project/leo_watchdog/releases/tag/0.8.0)
    * [savanna_agent v0.4.7](https://github.com/leo-project/savanna_agent/releases/tag/0.4.7)
    * [savanna_commons v0.8.10](https://github.com/leo-project/savanna_commons/releases/tag/0.8.10)
    * [erpcgen v0.2.3](https://github.com/leo-project/erpcgen/releases/tag/0.2.3)
    * [nfs_rpc_server v0.2.3](https://github.com/leo-project/nfs_rpc_server/releases/tag/0.2.3)
    * [leo_gateway v1.2.10](https://github.com/leo-project/leo_gateway/releases/tag/1.2.10)
    * [leo_manager v1.2.10](https://github.com/leo-project/leo_manager/releases/tag/1.2.10)
    * [leo_storage v1.2.10](https://github.com/leo-project/leo_storage/releases/tag/1.2.10)
* others
    * [bitcask v2.0.0](https://github.com/lbasho/bitcask/releases/tag/2.0.0)
    * [cowboy v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [cowlib v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [elarm v0.3.0](https://github.com/leo-project/elarm/releases/tag/0.3.0)
    * [eleveldb v1.4.10](https://github.com/basho/eleveldb/releases/tag/1.4.10)
    * [folsom v0.8.1](https://github.com/boundary/folsom/releases/tag/0.8.1)
    * [jiffy v0.13.3](https://github.com/davisp/jiffy/releases/tag/0.13.3)
    * [lz4 v0.2.2](https://github.com/leo-project/erlang-lz4/releases/tag/0.2.2) - forked from [szktty/erlang-lz4](https://github.com/szktty/erlng-lz4)
    * [recon v0.8.5](https://github.com/ferd/recon/releases/tag/2.2.1)

1.2.9
=====

Features and Improvements for LeoFS
-----------------------------------

* Improvements
    * [#354](https://github.com/leo-project/leofs/issues/354) ``leo_gateway`` ``leo_storage`` Exit when the number of retries reached a certain time
    * [#356](https://github.com/leo-project/leofs/issues/356) ``leo_object_storage`` Implemented output of a low I/O operation's log
    * [#358](https://github.com/leo-project/leofs/issues/358) ``leo_watchdog`` ``leo_manager`` Implemented changing configuration by leo_manager's console
    * [#360](https://github.com/leo-project/leofs/issues/360) ``leo_gateway`` Replace ``erlang:now`` with ``os:timestamp`` to improve the performance

Bugs Fixed
-----------

* Improve performance of recover-node and rebalance processing
    * [#359](https://github.com/leo-project/leofs/issues/359) ``leo_mq`` ``leo_storage`` CPU can be bottleneck in case doing ``rebalance/recover``
    * [#362](https://github.com/leo-project/leofs/issues/362) ``leo_backend_db`` ``leo_backend_db_bitcask:first/1`` function can use cpu more necessary
    * [Benchmark LeoFS v1.2.9 w/recover-node, watchdog and auto-compaction](https://github.com/leo-project/notes/tree/master/leofs/benchmark/leofs/recover_with_front/20150515_recover_node_1.2.9)
* [#361](https://github.com/leo-project/leofs/issues/361) ``leo_statistics`` ``leo_storage`` ``leo_gateway`` ``leo_manager`` All Leo's servers can start normally even if starting statistics related erlang processes failed

Used Libraries
---------------

* leo project
    * [leo_backend-db v1.1.7](https://github.com/leo-project/leo_backend_db/releases/tag/1.1.7)
    * [leo_cache v0.6.3](https://github.com/leo-project/leo_cache/releases/tag/0.6.3)
    * [leo_commons v1.1.1](https://github.com/leo-project/leo_commons/releases/tag/1.1.1)
    * [leo_dcerl v0.2.12](https://github.com/leo-project/leo_dcerl/releases/tag/0.2.12)
    * [leo_logger v1.1.5](https://github.com/leo-project/leo_logger/releases/tag/1.1.5)
    * [leo_mcerl v0.4.1](https://github.com/leo-project/leo_mcerl/releases/tag/0.4.1)
    * [leo_mq v1.3.8](https://github.com/leo-project/leo_mq/releases/tag/1.3.8)
    * [leo_object_storage v1.2.6](https://github.com/leo-project/leo_object_storage/releases/tag/1.2.6)
    * [leo_ordning_reda v1.0.0](https://github.com/leo-project/leo_ordning_reda/releases/tag/1.0.0)
    * [leo_redundant_manager 1.9.12](https://github.com/leo-project/leo_redundant_manager/releases/tag/1.9.12)
    * [leo_rpc v0.10.1](https://github.com/leo-project/leo_rpc/releases/tag/0.10.1)
    * [leo_pod v0.6.3](https://github.com/leo-project/leo_pod/releases/tag/0.6.3)
    * [leo_s3_libs v1.1.7](https://github.com/leo-project/leo_s3_libs/releases/tag/1.1.7)
    * [leo_statistics v1.1.3](https://github.com/leo-project/leo_statistics/releases/tag/1.1.3)
    * [leo_watchdog v0.8.0](https://github.com/leo-project/leo_watchdog/releases/tag/0.8.0)
    * [savanna_agent v0.4.6](https://github.com/leo-project/savanna_agent/releases/tag/0.4.6)
    * [savanna_commons v0.8.9](https://github.com/leo-project/savanna_commons/releases/tag/0.8.9)
    * [erpcgen v0.2.3](https://github.com/leo-project/erpcgen/releases/tag/0.2.3)
    * [nfs_rpc_server v0.2.3](https://github.com/leo-project/nfs_rpc_server/releases/tag/0.2.3)
    * [leo_gateway v1.2.9](https://github.com/leo-project/leo_gateway/releases/tag/1.2.9)
    * [leo_manager v1.2.9](https://github.com/leo-project/leo_manager/releases/tag/1.2.9)
    * [leo_storage v1.2.9](https://github.com/leo-project/leo_storage/releases/tag/1.2.9)
* others
    * [bitcask v2.0.0](https://github.com/lbasho/bitcask/releases/tag/2.0.0)
    * [cowboy v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [cowlib v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [elarm v0.3.0](https://github.com/leo-project/elarm/releases/tag/0.3.0)
    * [eleveldb v1.4.10](https://github.com/basho/eleveldb/releases/tag/1.4.10)
    * [folsom v0.8.1](https://github.com/boundary/folsom/releases/tag/0.8.1)
    * [jiffy v0.13.3](https://github.com/davisp/jiffy/releases/tag/0.13.3)
    * [lz4 v0.2.2](https://github.com/leo-project/erlang-lz4/releases/tag/0.2.2) - forked from [szktty/erlang-lz4](https://github.com/szktty/erlng-lz4)
    * [recon v0.8.5](https://github.com/ferd/recon/releases/tag/2.2.1)

1.2.8
=====

Features and Improvements for LeoFS
-----------------------------------

* Improvements
    * [#347](https://github.com/leo-project/leofs/issues/347) Delete Multiple Objects method of S3 API support
    * Implemented the mq-stats command for JSON format

Bugs Fixed
-----------

* Multi Data Center related issues
    * [#329](https://github.com/leo-project/leofs/issues/329) ``mdc-replication`` Wrong cluster-status when executing the command on a remote-cluster's manager
    * [#343](https://github.com/leo-project/leofs/issues/343) ``leo_storage`` ``mdc`` Replication messages coudn't be consumed at all
    * [#345](https://github.com/leo-project/leofs/issues/345) ``leo_storage`` ``mdc`` Replication DELETE messages coudn't be consumed properly when the target objects already have been compacted
* Storage related issues
    * [#333](https://github.com/leo-project/leofs/issues/333) ``leo_storage`` "case_clause" could happen when the target object was already deleted
    * [#344](https://github.com/leo-project/leofs/issues/344) ``leo_storage`` Refactor leo_storage_handler_object to reduce complexity
* Gateway related issues
    * [#328](https://github.com/leo-project/leofs/issues/328) ``leo_gateway`` Cannot stop gateway with leo_gateway script
        * [#340](https://github.com/leo-project/leofs/issues/340) ``leo_gateway`` leo_gateway can't stop (kill -0) properly on OSX
    * [#348](https://github.com/leo-project/leofs/issues/348) ``leo_gateway`` Files uploaded with its name including urlencoded chars stored improper name
    * [#349](https://github.com/leo-project/leofs/issues/349) ``leo_gateway`` Get object with range header returns empty(wrong) content
* Othe issues
    * [#141](https://github.com/leo-project/leofs/issues/141) ``leo_rpc``Performance degradation due to leaking tcp connections

Used Libraries
---------------

* leo project
    * [leo_backend-db v1.1.6](https://github.com/leo-project/leo_backend_db/releases/tag/1.1.6)
    * [leo_cache v0.6.3](https://github.com/leo-project/leo_cache/releases/tag/0.6.3)
    * [leo_commons v1.1.1](https://github.com/leo-project/leo_commons/releases/tag/1.1.1)
    * [leo_dcerl v0.2.12](https://github.com/leo-project/leo_dcerl/releases/tag/0.2.12)
    * [leo_logger v1.1.5](https://github.com/leo-project/leo_logger/releases/tag/1.1.5)
    * [leo_mcerl v0.4.1](https://github.com/leo-project/leo_mcerl/releases/tag/0.4.1)
    * [leo_mq v1.3.6](https://github.com/leo-project/leo_mq/releases/tag/1.3.6)
    * [leo_object_storage v1.2.5](https://github.com/leo-project/leo_object_storage/releases/tag/1.2.5)
    * [leo_ordning_reda v1.0.0](https://github.com/leo-project/leo_ordning_reda/releases/tag/1.0.0)
    * [leo_redundant_manager 1.9.10](https://github.com/leo-project/leo_redundant_manager/releases/tag/1.9.10)
    * [leo_rpc v0.10.1](https://github.com/leo-project/leo_rpc/releases/tag/0.10.1)
    * [leo_pod v0.6.3](https://github.com/leo-project/leo_pod/releases/tag/0.6.3)
    * [leo_s3_libs v1.1.7](https://github.com/leo-project/leo_s3_libs/releases/tag/1.1.7)
    * [leo_statistics v1.1.2](https://github.com/leo-project/leo_statistics/releases/tag/1.1.2)
    * [leo_watchdog v0.6.4](https://github.com/leo-project/leo_watchdog/releases/tag/0.6.4)
    * [savanna_agent v0.4.6](https://github.com/leo-project/savanna_agent/releases/tag/0.4.6)
    * [savanna_commons v0.8.9](https://github.com/leo-project/savanna_commons/releases/tag/0.8.9)
    * [erpcgen v0.2.3](https://github.com/leo-project/erpcgen/releases/tag/0.2.3)
    * [nfs_rpc_server v0.2.3](https://github.com/leo-project/nfs_rpc_server/releases/tag/0.2.3)
    * [leo_gateway v1.2.8](https://github.com/leo-project/leo_gateway/releases/tag/1.2.8)
    * [leo_manager v1.2.8](https://github.com/leo-project/leo_manager/releases/tag/1.2.8)
    * [leo_storage v1.2.8](https://github.com/leo-project/leo_storage/releases/tag/1.2.8)
* others
    * [bitcask v1.7.1](https://github.com/leo-project/bitcask/releases/tag/1.7.1)
    * [cowboy v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [cowlib v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [elarm v0.3.0](https://github.com/leo-project/elarm/releases/tag/0.3.0)
    * [eleveldb v1.4.10](https://github.com/basho/eleveldb/releases/tag/1.4.10)
    * [folsom v0.8.1](https://github.com/boundary/folsom/releases/tag/0.8.1)
    * [jiffy v0.13.3](https://github.com/davisp/jiffy/releases/tag/0.13.3)
    * [lz4 v0.2.2](https://github.com/leo-project/erlang-lz4/releases/tag/0.2.2) - forked from [szktty/erlang-lz4](https://github.com/szktty/erlng-lz4)
    * [recon v0.8.5](https://github.com/ferd/recon/releases/tag/2.2.1)

1.2.7
=====

Features and Improvements for LeoFS
-----------------------------------

* [#320](https://github.com/leo-project/leofs/issues/320) ``leo_mq`` Can take too much time to get started consuming messages in a MQ

Bugs Fixed
-----------

* [#313](https://github.com/leo-project/leofs/issues/313) ``leo_watchdog`` Watchdog downed every an hour
* [#315](https://github.com/leo-project/leofs/issues/315) ``leo_redundant_manager`` Inconsistent storage node status
* [#317](https://github.com/leo-project/leofs/issues/317) ``leo_redundant_manager`` Calling leo_manager_api:get_members_of_all_versions get timeout on leo_gateway
* [#319](https://github.com/leo-project/leofs/issues/319) ``leo_gateway`` List Objects with ``next-marker`` could NOT work when using ``s3cmd`` as a client
* [#322](https://github.com/leo-project/leofs/issues/322) ``leo_cache`` Set wrong value to a disk cache capacity
* [#323](https://github.com/leo-project/leofs/issues/323) ``leo_dcerl`` LeoFS's gateway do not response or return HTTP error code 5xx

Used Libraries
---------------

* leo project
    * [leo_backend-db v1.1.5](https://github.com/leo-project/leo_backend_db/releases/tag/1.1.5)
    * [leo_cache v0.6.3](https://github.com/leo-project/leo_cache/releases/tag/0.6.3)
    * [leo_commons v1.1.1](https://github.com/leo-project/leo_commons/releases/tag/1.1.1)
    * [leo_dcerl v0.2.12](https://github.com/leo-project/leo_dcerl/releases/tag/0.2.12)
    * [leo_logger v1.1.5](https://github.com/leo-project/leo_logger/releases/tag/1.1.5)
    * [leo_mcerl v0.4.1](https://github.com/leo-project/leo_mcerl/releases/tag/0.4.1)
    * [leo_mq v1.3.4](https://github.com/leo-project/leo_mq/releases/tag/1.3.4)
    * [leo_object_storage v1.2.4](https://github.com/leo-project/leo_object_storage/releases/tag/1.2.4)
    * [leo_ordning_reda v0.10.10](https://github.com/leo-project/leo_ordning_reda/releases/tag/0.10.10)
    * [leo_redundant_manager 1.9.8](https://github.com/leo-project/leo_redundant_manager/releases/tag/1.9.8)
    * [leo_rpc v0.10.0](https://github.com/leo-project/leo_rpc/releases/tag/0.10.0)
    * [leo_pod v0.6.2](https://github.com/leo-project/leo_pod/releases/tag/0.6.2)
    * [leo_s3_libs v1.1.6](https://github.com/leo-project/leo_s3_libs/releases/tag/1.1.6)
    * [leo_statistics v1.1.0](https://github.com/leo-project/leo_statistics/releases/tag/1.1.0)
    * [leo_watchdog v0.6.3](https://github.com/leo-project/leo_watchdog/releases/tag/0.6.3)
    * [savanna_agent v0.4.5](https://github.com/leo-project/savanna_agentreleases/tag/0.4.5)
    * [savanna_commons v0.8.7](https://github.com/leo-project/savanna_commons/releases/tag/0.8.7)
    * [erpcgen v0.2.3](https://github.com/leo-project/erpcgen/releases/tag/0.2.3)
    * [nfs_rpc_server v0.2.3](https://github.com/leo-project/nfs_rpc_server/releases/tag/0.2.3)
    * [leo_gateway v1.2.7](https://github.com/leo-project/leo_gateway/releases/tag/1.2.7)
    * [leo_manager v1.2.7](https://github.com/leo-project/leo_manager/releases/tag/1.2.7)
    * [leo_storage v1.2.7](https://github.com/leo-project/leo_storage/releases/tag/1.2.7)
* others
    * [bitcask v1.7.1](https://github.com/leo-project/bitcask/releases/tag/1.7.1)
    * [cowboy v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [cowlib v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [elarm v0.3.0](https://github.com/leo-project/elarm/releases/tag/0.3.0)
    * [eleveldb v1.4.10](https://github.com/basho/eleveldb/releases/tag/1.4.10)
    * [folsom v0.8.1](https://github.com/boundary/folsom/releases/tag/0.8.1)
    * [jiffy v0.13.3](https://github.com/davisp/jiffy/releases/tag/0.13.3)
    * [lz4 v0.2.2](https://github.com/leo-project/erlang-lz4/releases/tag/0.2.2) - forked from [szktty/erlang-lz4](https://github.com/szktty/erlng-lz4)
    * [recon v0.8.5](https://github.com/ferd/recon/releases/tag/2.2.1)

1.2.6
=====

Features and Improvements for LeoFS
-----------------------------------

* [#296](https://github.com/leo-project/leofs/issues/296) ``leo_commons`` Replace leo_hashtable with Erlang built-in function
* [#305](https://github.com/leo-project/leofs/issues/305) ``leo_statistics`` some system metrics should be added for more reliability

Bugs Fixed
-----------

* [#307](https://github.com/leo-project/leofs/issues/307) ``leo_storage`` Could not respond not existed object immediately (LeoFS v1.2.5's bug)
    * LeoFS Gateway was timeout because LeoFS Storage could not respond not existed object immediately.
And also, load of a primary of storage-node became high by this issue.
    * We took measure for this situation we implemented [leofs_test2](https://github.com/leo-project/leofs_test2) which is an integration test tool.
* [#308](https://github.com/leo-project/leofs/issues/308) ``leo_storage`` ``leo_gateway`` Could not synchronize 'suspend' status at each gateway and storage nodes
* [#309](https://github.com/leo-project/leofs/issues/309) ``leo_redundant_manager`` ``leo_manager`` Ring status to be synced between mnesia and worker state
* [#310](https://github.com/leo-project/leofs/issues/310) ``leo_gateway`` Delete request might consume CPU resource more than necessary
* [#311](https://github.com/leo-project/leofs/issues/311) ``leo_storage`` Could NOT respond an object when facing the inconsistent object

Used Libraries
---------------

* leo project
    * [leo_backend-db v1.1.4](https://github.com/leo-project/leo_backend_db/releases/tag/1.1.4)
    * [leo_cache v0.6.0](https://github.com/leo-project/leo_cache/releases/tag/0.6.0)
    * [leo_commons v1.1.0](https://github.com/leo-project/leo_commons/releases/tag/1.1.0)
    * [leo_dcerl v0.2.11](https://github.com/leo-project/leo_dcerl/releases/tag/0.2.11)
    * [leo_logger v1.1.4](https://github.com/leo-project/leo_logger/releases/tag/1.1.4)
    * [leo_mcerl v0.4.1](https://github.com/leo-project/leo_mcerl/releases/tag/0.4.1)
    * [leo_mq v1.3.3](https://github.com/leo-project/leo_mq/releases/tag/1.3.3)
    * [leo_object_storage v1.2.3](https://github.com/leo-project/leo_object_storage/releases/tag/1.2.3)
    * [leo_ordning_reda v0.10.9](https://github.com/leo-project/leo_ordning_reda/releases/tag/0.10.9)
    * [leo_redundant_manager 1.9.7](https://github.com/leo-project/leo_redundant_manager/releases/tag/1.9.7)
    * [leo_rpc v0.8.10](https://github.com/leo-project/leo_rpc/releases/tag/0.8.10)
    * [leo_pod v0.6.2](https://github.com/leo-project/leo_pod/releases/tag/0.6.2)
    * [leo_s3_libs v1.1.5](https://github.com/leo-project/leo_s3_libs/releases/tag/1.1.5)
    * [leo_statistics v1.0.9](https://github.com/leo-project/leo_statistics/releases/tag/1.0.9)
    * [leo_watchdog v0.6.2](https://github.com/leo-project/leo_watchdog/releases/tag/0.6.2)
    * [savanna_agent v0.4.4](https://github.com/leo-project/savanna_agentreleases/tag/0.4.4)
    * [savanna_commons v0.8.6](https://github.com/leo-project/savanna_commons/releases/tag/0.8.6)
    * [erpcgen v0.2.3](https://github.com/leo-project/erpcgen/releases/tag/0.2.3)
    * [nfs_rpc_server v0.2.2](https://github.com/leo-project/nfs_rpc_server/releases/tag/0.2.2)
    * [leo_gateway v1.2.6](https://github.com/leo-project/leo_gateway/releases/tag/1.2.6)
    * [leo_manager v1.2.6](https://github.com/leo-project/leo_manager/releases/tag/1.2.6)
    * [leo_storage v1.2.6](https://github.com/leo-project/leo_storage/releases/tag/1.2.6)
* others
    * [bitcask v1.7.1](https://github.com/leo-project/bitcask/releases/tag/1.7.1)
    * [cowboy v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [cowlib v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [elarm v0.3.0](https://github.com/leo-project/elarm/releases/tag/0.3.0)
    * [eleveldb v1.4.10](https://github.com/basho/eleveldb/releases/tag/1.4.10)
    * [folsom v0.8.1](https://github.com/boundary/folsom/releases/tag/0.8.1)
    * [jiffy v0.8.5](https://github.com/davisp/jiffy/releases/tag/0.2.2)
    * [lz4 v0.2.2](https://github.com/leo-project/erlang-lz4/releases/tag/0.2.2) - forked from [szktty/erlang-lz4](https://github.com/szktty/erlng-lz4)
    * [recon v0.8.5](https://github.com/ferd/recon/releases/tag/2.2.1)

1.2.5
=====

Features and Improvements for LeoFS
-----------------------------------

* Started to provide LeoFS integration test tool - [leofs_test](https://github.com/leo-project/leofs_test2)
    * We're able to easily check LeoFS with it whether latest LeoFS has issues or not before getting installed LeoFS in your dev/staging/production environment(s).

Bugs Fixed
-----------

* [#299](https://github.com/leo-project/leofs/issues/299) ``leo_redundant_manager`` Inconsistent ring of a resumed storage-node which is timing issue
* [#301](https://github.com/leo-project/leofs/issues/301) ``leo_storage`` Replication messages could be lost in some edge cases
* ``leo_storage`` Fix the read-and-repair mechanism. Some inconsistent data could not recover with it.

Used Libraries
---------------

* leo project
    * [leo_backend-db v1.1.4](https://github.com/leo-project/leo_backend_db/releases/tag/1.1.4)
    * [leo_cache v0.6.0](https://github.com/leo-project/leo_cache/releases/tag/0.6.0)
    * [leo_commons v1.1.0](https://github.com/leo-project/leo_commons/releases/tag/1.1.0)
    * [leo_dcerl v0.2.11](https://github.com/leo-project/leo_dcerl/releases/tag/0.2.11)
    * [leo_logger v1.1.4](https://github.com/leo-project/leo_logger/releases/tag/1.1.4)
    * [leo_mcerl v0.4.1](https://github.com/leo-project/leo_mcerl/releases/tag/0.4.1)
    * [leo_mq v1.3.3](https://github.com/leo-project/leo_mq/releases/tag/1.3.3)
    * [leo_object_storage v1.2.3](https://github.com/leo-project/leo_object_storage/releases/tag/1.2.3)
    * [leo_ordning_reda v0.10.9](https://github.com/leo-project/leo_ordning_reda/releases/tag/0.10.9)
    * [leo_redundant_manager 1.9.6](https://github.com/leo-project/leo_redundant_manager/releases/tag/1.9.6)
    * [leo_rpc v0.8.10](https://github.com/leo-project/leo_rpc/releases/tag/0.8.10)
    * [leo_pod v0.6.2](https://github.com/leo-project/leo_pod/releases/tag/0.6.2)
    * [leo_s3_libs v1.1.5](https://github.com/leo-project/leo_s3_libs/releases/tag/1.1.5)
    * [leo_statistics v1.0.8](https://github.com/leo-project/leo_statistics/releases/tag/1.0.8)
    * [leo_watchdog v0.6.2](https://github.com/leo-project/leo_watchdog/releases/tag/0.6.2)
    * [savanna_agent v0.4.4](https://github.com/leo-project/savanna_agentreleases/tag/0.4.4)
    * [savanna_commons v0.8.6](https://github.com/leo-project/savanna_commons/releases/tag/0.8.6)
    * [erpcgen v0.2.3](https://github.com/leo-project/erpcgen/releases/tag/0.2.3)
    * [nfs_rpc_server v0.2.2](https://github.com/leo-project/nfs_rpc_server/releases/tag/0.2.2)
    * [leo_gateway v1.2.5](https://github.com/leo-project/leo_gateway/releases/tag/1.2.5)
    * [leo_manager v1.2.5](https://github.com/leo-project/leo_manager/releases/tag/1.2.5)
    * [leo_storage v1.2.5](https://github.com/leo-project/leo_storage/releases/tag/1.2.5)
* others
    * [bitcask v1.7.1](https://github.com/leo-project/bitcask/releases/tag/1.7.1)
    * [cowboy v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [cowlib v1.0.0](https://github.com/extend/cowboy/releases/tag/1.0.0)
    * [elarm v0.3.0](https://github.com/leo-project/elarm/releases/tag/0.3.0)
    * [eleveldb v1.4.10](https://github.com/basho/eleveldb/releases/tag/1.4.10)
    * [folsom v0.8.1](https://github.com/boundary/folsom/releases/tag/0.8.1)
    * [jiffy v0.8.5](https://github.com/davisp/jiffy/releases/tag/0.2.2)
    * [lz4 v0.2.2](https://github.com/leo-project/erlang-lz4/releases/tag/0.2.2) - forked from [szktty/erlang-lz4](https://github.com/szktty/erlng-lz4)

1.2.4
=====

Bugs Fixed
-----------

* [#297](https://github.com/leo-project/leofs/issues/297) ``leo_object_storage`` Could NOT handle delete requests which made by the MQ mechanism at LeoFS v1.2.3

Used Libraries
---------------

* leo project
    * [leo_backend-db v1.1.4](https://github.com/leo-project/leo_backend_db.git)
    * [leo_cache v0.6.0](https://github.com/leo-project/leo_cache.git)
    * [leo_commons v1.1.0](https://github.com/leo-project/leo_commons.git)
    * [leo_dcerl v0.2.11](https://github.com/leo-project/leo_dcerl.git)
    * [leo_logger v1.1.4](https://github.com/leo-project/leo_logger.git)
    * [leo_mcerl v0.4.1](https://github.com/leo-project/leo_mcerl.git)
    * [leo_mq v1.3.3](https://github.com/leo-project/leo_mq.git)
    * [leo_object_storage v1.2.3](https://github.com/leo-project/leo_object_storage.git)
    * [leo_ordning_reda v0.10.9](https://github.com/leo-project/leo_ordning_reda.git)
    * [leo_redundant_manager 1.9.5](https://github.com/leo-project/leo_redundant_manager.git)
    * [leo_rpc v0.8.10](https://github.com/leo-project/leo_rpc.git)
    * [leo_pod v0.6.2](https://github.com/leo-project/leo_pod.git)
    * [leo_s3_libs v1.1.5](https://github.com/leo-project/leo_s3_libs.git)
    * [leo_statistics v1.0.8](https://github.com/leo-project/leo_statistics.git)
    * [leo_watchdog v0.6.1](https://github.com/leo-project/leo_watchdog.git)
    * [savanna_agent v0.4.4](https://github.com/leo-project/savanna_agent.git)
    * [savanna_commons v0.8.6](https://github.com/leo-project/savanna_commons.git)
    * [erpcgen v0.2.3](https://github.com/leo-project/erpcgen.git)
    * [nfs_rpc_server v0.2.2](https://github.com/leo-project/nfs_rpc_server.git)
    * [leo_gateway v1.2.4](https://github.com/leo-project/leo_gateway.git)
    * [leo_manager v1.2.4](https://github.com/leo-project/leo_manager.git)
    * [leo_storage v1.2.4](https://github.com/leo-project/leo_storage.git)
* others
    * [bitcask v1.7.1](https://github.com/leo-project/bitcask.git)
    * [cowboy v1.0.0](https://github.com/extend/cowboy.git)
    * [cowlib v1.0.0](https://github.com/extend/cowboy.git)
    * [elarm v0.3.0](https://github.com/leo-project/elarm.git)
    * [eleveldb v1.4.10](https://github.com/basho/eleveldb.git)
    * [folsom v0.8.1](https://github.com/boundary/folsom.git)
    * [jiffy v0.8.5](https://github.com/davisp/jiffy.git)
    * [lz4 v0.2.2](https://github.com/leo-project/erlang-lz4.git) - forked from [szktty/erlang-lz4](https://github.com/szktty/erlng-lz4)

1.2.3
=====

Features and Improvements for LeoFS
-----------------------------------

* Improvements
    * [#285](https://github.com/leo-project/leofs/issues/285) ``leo_storage`` Implemented "cluster-watchdog" in order to keep best condition of a cluster
    * [#286](https://github.com/leo-project/leofs/issues/286) ``leo_storage`` Unified name of configuration items for the mq and the compaction

Bugs Fixed
-----------

* [#288](https://github.com/leo-project/leofs/issues/288) ``leo_manager`` Fixed wrong mix/max values when issueing [the status <storage-node> command](http://leo-project.net/leofs/docs/admin_guide/admin_guide_2.html#status-command) with ``leofs-adm command``
* [#290](https://github.com/leo-project/leofs/issues/290) [the du detail <storage-node> command](http://leo-project.net/leofs/docs/admin_guide/admin_guide_5.html#du-detail) with ``leofs-adm command`` had broken 1.2.2
* [#292](https://github.com/leo-project/leofs/issues/292) ``leo_storage`` [proc_lib:start_link](http://erlang.org/doc/man/proc_lib.html#spawn_link-1) must be used instead of [erlang:spawn](http://erlang.org/doc/man/erlang.html#spawn-1)
* [#293](https://github.com/leo-project/leofs/issues/293) Fixed that remain objects after finished data-compaction, situation of which is combination auto-compaction and deletion of a bucket

Used Libraries
---------------

* leo project
    * [leo_backend-db v1.1.4](https://github.com/leo-project/leo_backend_db.git)
    * [leo_cache v0.6.0](https://github.com/leo-project/leo_cache.git)
    * [leo_commons v1.1.0](https://github.com/leo-project/leo_commons.git)
    * [leo_dcerl v0.2.11](https://github.com/leo-project/leo_dcerl.git)
    * [leo_logger v1.1.4](https://github.com/leo-project/leo_logger.git)
    * [leo_mcerl v0.4.1](https://github.com/leo-project/leo_mcerl.git)
    * [leo_mq v1.3.3](https://github.com/leo-project/leo_mq.git)
    * [leo_object_storage v1.2.2](https://github.com/leo-project/leo_object_storage.git)
    * [leo_ordning_reda v0.10.9](https://github.com/leo-project/leo_ordning_reda.git)
    * [leo_redundant_manager 1.9.5](https://github.com/leo-project/leo_redundant_manager.git)
    * [leo_rpc v0.8.10](https://github.com/leo-project/leo_rpc.git)
    * [leo_pod v0.6.2](https://github.com/leo-project/leo_pod.git)
    * [leo_s3_libs v1.1.5](https://github.com/leo-project/leo_s3_libs.git)
    * [leo_statistics v1.0.8](https://github.com/leo-project/leo_statistics.git)
    * [leo_watchdog v0.6.1](https://github.com/leo-project/leo_watchdog.git)
    * [savanna_agent v0.4.4](https://github.com/leo-project/savanna_agent.git)
    * [savanna_commons v0.8.6](https://github.com/leo-project/savanna_commons.git)
    * [erpcgen v0.2.3](https://github.com/leo-project/erpcgen.git)
    * [nfs_rpc_server v0.2.2](https://github.com/leo-project/nfs_rpc_server.git)
    * [leo_gateway v1.2.3](https://github.com/leo-project/leo_gateway.git)
    * [leo_manager v1.2.3](https://github.com/leo-project/leo_manager.git)
    * [leo_storage v1.2.3](https://github.com/leo-project/leo_storage.git)
* others
    * [bitcask v1.7.1](https://github.com/leo-project/bitcask.git)
    * [cowboy v1.0.0](https://github.com/extend/cowboy.git)
    * [cowlib v1.0.0](https://github.com/extend/cowboy.git)
    * [elarm v0.3.0](https://github.com/leo-project/elarm.git)
    * [eleveldb v1.4.10](https://github.com/basho/eleveldb.git)
    * [folsom v0.8.1](https://github.com/boundary/folsom.git)
    * [jiffy v0.8.5](https://github.com/davisp/jiffy.git)
    * [lz4 v0.2.2](https://github.com/leo-project/erlang-lz4.git) - forked from [szktty/erlang-lz4](https://github.com/szktty/erlng-lz4)

1.2.2
=====

Features and Improvements for LeoFS
-----------------------------------

* New Features
    * [#117](https://github.com/leo-project/leofs/issues/117) ``leo_storage`` Implemented the auto-compaction mechanism
      * The auto-compaction configuration file for [LeoFS Storage](https://github.com/leo-project/leo_storage/blob/develop/priv/leo_storage.conf#L139-L152), name of which is ``leo_storage.conf``
      * The auto-compaction configuration is as follows:
      ```bash
      ## [compaction] enabled compaction? - default:false
      autonomic_op.compaction.is_enabled = true

      ## [compaction] number of parallel procs - default:1
      autonomic_op.compaction.parallel_procs = 1

      ## [compaction] warning ratio of active size - default:70%
      autonomic_op.compaction.warn_active_size_ratio = 70

      ## [compaction] threshold ratio of active size - default:60%
      autonomic_op.compaction.threshold_active_size_ratio = 60
      ```
* Improvements
    * [#270](https://github.com/leo-project/leofs/issues/270) Supported leo_watchdog for FreeBSD and SmartOS
    * [#281](https://github.com/leo-project/leofs/issues/281) ``leo_gateway`` Made timeout configurable for the get and the find_by_parent_dir
    * The watchdog mechnism to production status
      * The watchdog configuration file for [LeoFS Storage](https://github.com/leo-project/leo_storage/blob/develop/priv/leo_storage.conf#L63-L136) and [LeoFS Gateway](https://github.com/leo-project/leo_gateway/blob/develop/priv/leo_gateway.conf#L161-L206), name of which are ``leo_storage.conf`` and ``leo_gateway.conf``
      * The watchdog configuration for CPU and Disk as follows:
      ```bash
      ##  Watchdog.CPU
      ##
      ## Is cpu-watchdog enabled - default:false
      watchdog.cpu.is_enabled = true

      ## cpu - raised error times
      watchdog.cpu.raised_error_times = 3

      ## cpu - watch interval - default:5sec
      watchdog.cpu.interval = 5

      ## Threshold CPU load avg for 1min/5min - default:5.0
      watchdog.cpu.threshold_cpu_load_avg = 5.0

      ## Threshold CPU load util - default:100 = "100%"
      watchdog.cpu.threshold_cpu_util = 100

      ##  Watchdog.DISK
      ##
      ## Is disk-watchdog enabled - default:false
      watchdog.disk.is_enabled = true

      ## disk - raised error times
      watchdog.disk.raised_error_times = 3

      ## disk - watch interval - default:1sec
      watchdog.disk.interval = 1

      ## Threshold disk use% - defalut:85%
      watchdog.disk.threshold_disk_use = 85

      ## Threshold disk util% - defalut:100%
      watchdog.disk.threshold_disk_util = 100

      ## Threshold disk read kb/sec - defalut:262144(KB)
      watchdog.disk.threshold_disk_rkb = 262144

      ## Threshold disk write kb/sec - defalut:262144(KB)
      watchdog.disk.threshold_disk_wkb = 262144

      ## disk target devices for checking disk utilization
      watchdog.disk.target_devices = []
      ```
      * Improved MQ's confurations for LeoFS Stroage in order to be able to control system load
      ```bash
      ## [Number of bach processes of message]
      ##
      ## Minimum number of bach processes of message
      mq.num_of_batch_process_min = 100

      ## Maxmim  number of bach processes of message
      mq.num_of_batch_process_max = 10000

      ## Maxmim  number of bach processes of message
      mq.num_of_batch_process_regular = 1000

      ## Maxmim  number of bach processes of message
      mq.num_of_batch_process_step = 250

      ## [Interval beween batch-procs]
      ##
      ## Minimum value of interval beween batch-procs(msec)
      mq.interval_between_batch_procs_min = 10

      ## Maximum value of interval between batch-procs(msec)
      mq.interval_between_batch_procs_max = 1000

      ## Regular value of interval between batch-procs(msec)
      mq.interval_between_batch_procs_regular = 300

      ## Step value of interval between batch-procs(msec)
      mq.interval_between_batch_procs_step = 100
      ```
      * Improved the ``mq-status`` command of ``leofs-adm``
      ```bash
      $ leofs-adm mq-stats storage_1@127.0.0.1
                    id                |    state    | number of msgs | batch of msgs  |    interval    |            description
      --------------------------------+-------------+----------------|----------------|----------------|-----------------------------------
      leo_delete_dir_queue            |   idling    | 0              | 1000           | 100            | delete directories
      leo_comp_meta_with_dc_queue     |   idling    | 0              | 1000           | 100            | compare metadata w/remote-node
      leo_sync_obj_with_dc_queue      |   idling    | 0              | 1000           | 100            | sync objs w/remote-node
      leo_recovery_node_queue         |   idling    | 0              | 1000           | 100            | recovery objs of node
      leo_async_deletion_queue        |   idling    | 0              | 1000           | 100            | async deletion of objs
      leo_rebalance_queue             |   running   | 2167           | 1400           | 10             | rebalance objs
      leo_sync_by_vnode_id_queue      |   idling    | 0              | 1000           | 100            | sync objs by vnode-id
      leo_per_object_queue            |   idling    | 0              | 1000           | 100            | recover inconsistent objs
       ```

Bugs Fixed
-----------

* [#273](https://github.com/leo-project/leofs/issues/273) ``leo_gateway`` ``NFS`` Max file size was hardcoded as 4GB
* [#274](https://github.com/leo-project/leofs/issues/274) ``leo_manager`` ``leo_storage`` ``leo_gateway`` Crashed a manager node by snmp-related issue with Erlang-17
* [#275](https://github.com/leo-project/leofs/issues/275) ``leo_gateawy`` An error message was output if there is no the http custom header file
* [#277](https://github.com/leo-project/leofs/issues/277) ``leo_gateway`` In REST mode, Putting a large object failed
* [#279](https://github.com/leo-project/leofs/issues/279) ``leo_object_storage`` Compaction status can be inconsistent when an error occured while preparing compaction
* [#282](https://github.com/leo-project/leofs/issues/282) ``leo_gateway`` Gateway's timeout configuration has been ignored

Used Libraries
---------------

* leo project
    * [leo_backend-db v1.1.4](https://github.com/leo-project/leo_backend_db.git)
    * [leo_cache v0.6.0](https://github.com/leo-project/leo_cache.git)
    * [leo_commons v1.1.0](https://github.com/leo-project/leo_commons.git)
    * [leo_dcerl v0.2.11](https://github.com/leo-project/leo_dcerl.git)
    * [leo_logger v1.1.4](https://github.com/leo-project/leo_logger.git)
    * [leo_mcerl v0.4.1](https://github.com/leo-project/leo_mcerl.git)
    * [leo_mq v1.3.0](https://github.com/leo-project/leo_mq.git)
    * [leo_object_storage v1.2.0](https://github.com/leo-project/leo_object_storage.git)
    * [leo_ordning_reda v0.10.9](https://github.com/leo-project/leo_ordning_reda.git)
    * [leo_redundant_manager 1.9.2](https://github.com/leo-project/leo_redundant_manager.git)
    * [leo_rpc v0.8.10](https://github.com/leo-project/leo_rpc.git)
    * [leo_pod v0.6.2](https://github.com/leo-project/leo_pod.git)
    * [leo_s3_libs v1.1.5](https://github.com/leo-project/leo_s3_libs.git)
    * [leo_statistics v1.0.7](https://github.com/leo-project/leo_statistics.git)
    * [leo_watchdog v0.6.0](https://github.com/leo-project/leo_watchdog.git)
    * [savanna_agent v0.4.4](https://github.com/leo-project/savanna_agent.git)
    * [savanna_commons v0.8.6](https://github.com/leo-project/savanna_commons.git)
    * [erpcgen v0.2.3](https://github.com/leo-project/erpcgen.git)
    * [nfs_rpc_server v0.2.2](https://github.com/leo-project/nfs_rpc_server.git)
    * [leo_gateway v1.2.2](https://github.com/leo-project/leo_gateway.git)
    * [leo_manager v1.2.2](https://github.com/leo-project/leo_manager.git)
    * [leo_storage v1.2.2](https://github.com/leo-project/leo_storage.git)
* others
    * [bitcask v1.7.1](https://github.com/leo-project/bitcask.git)
    * [cowboy v1.0.0](https://github.com/extend/cowboy.git)
    * [cowlib v1.0.0](https://github.com/extend/cowboy.git)
    * [elarm v0.3.0](https://github.com/leo-project/elarm.git)
    * [eleveldb v1.4.10](https://github.com/basho/eleveldb.git)
    * [folsom v0.8.1](https://github.com/boundary/folsom.git)
    * [jiffy v0.8.5](https://github.com/davisp/jiffy.git)
    * [lz4 v0.2.2](https://github.com/leo-project/erlang-lz4.git) - forked from [szktty/erlang-lz4](https://github.com/szktty/erlng-lz4)

1.2.1
=====

Features and Improvements for LeoFS
-----------------------------------

* Improvements
    * Supported [LeoCenter](https://github.com/leo-project/leo_center) for LeoFS v1.2

Bugs Fixed
-----------

* Fixed system migration issue from v1.x to v1.2.0

Used Libraries
---------------

* leo project
    * [leo_backend-db v1.1.3](https://github.com/leo-project/leo_backend_db.git)
    * [leo_cache v0.6.0](https://github.com/leo-project/leo_cache.git)
    * [leo_commons v1.1.0](https://github.com/leo-project/leo_commons.git)
    * [leo_dcerl v0.2.11](https://github.com/leo-project/leo_dcerl.git)
    * [leo_logger v1.1.3](https://github.com/leo-project/leo_logger.git)
    * [leo_mcerl v0.4.1](https://github.com/leo-project/leo_mcerl.git)
    * [leo_mq v1.2.0](https://github.com/leo-project/leo_mq.git)
    * [leo_object_storage v1.1.8](https://github.com/leo-project/leo_object_storage.git)
    * [leo_ordning_reda v0.10.9](https://github.com/leo-project/leo_ordning_reda.git)
    * [leo_redundant_manager 1.9.1](https://github.com/leo-project/leo_redundant_manager.git)
    * [leo_rpc v0.8.10](https://github.com/leo-project/leo_rpc.git)
    * [leo_pod v0.6.2](https://github.com/leo-project/leo_pod.git)
    * [leo_s3_libs v1.1.4](https://github.com/leo-project/leo_s3_libs.git)
    * [leo_statistics v1.0.7](https://github.com/leo-project/leo_statistics.git)
    * [leo_watchdog v0.4.1](https://github.com/leo-project/leo_watchdog.git)
    * [savanna_agent v0.4.4](https://github.com/leo-project/savanna_agent.git)
    * [savanna_commons v0.8.6](https://github.com/leo-project/savanna_commons.git)
    * [erpcgen v0.2.3](https://github.com/leo-project/erpcgen.git)
    * [nfs_rpc_server v0.2.2](https://github.com/leo-project/nfs_rpc_server.git)
    * [leo_gateway v1.2.1](https://github.com/leo-project/leo_gateway.git)
    * [leo_manager v1.2.1](https://github.com/leo-project/leo_manager.git)
    * [leo_storage v1.2.1](https://github.com/leo-project/leo_storage.git)
* others
    * [bitcask v1.7.0](https://github.com/basho/bitcask.git)
    * [cowboy v1.0.0](https://github.com/extend/cowboy.git)
    * [cowlib v1.0.0](https://github.com/extend/cowboy.git)
    * [elarm v0.3.0](https://github.com/leo-project/elarm.git)
    * [eleveldb v1.4.10](https://github.com/basho/eleveldb.git)
    * [folsom v0.8.1](https://github.com/boundary/folsom.git)
    * [jiffy v0.8.5](https://github.com/davisp/jiffy.git)
    * [lz4 v0.2.2](https://github.com/leo-project/erlang-lz4.git) - forked from [szktty/erlang-lz4](https://github.com/szktty/erlng-lz4)

1.2.0
=====

Features and Improvements for LeoFS
-----------------------------------

* New Features
    * Watchdog mechnism has been implemented, which is called [leo_watchdog](https://github.com/leo-project/leo_watchdog)
        * Target resources: [cpu, io, disk]
        * Status: Beta
        * Requirements: CentOS-6.5 later and Ubuntu-13.10/14.04 later
        * Furure plan: Support FreeBSD and SmartOS with v1.2.1
* Improved
    * [#121](https://github.com/leo-project/leofs/issues/121) Tool to migrate metadata dbs from bitcask to leveldb
    * [#166](https://github.com/leo-project/leofs/issues/166) ``leo_rpc`` ``leo_storage`` Multi DC replication messages could lost
    * [#202](https://github.com/leo-project/leofs/issues/202) ``leo_gateway`` Made timeout configurable
    * [#239](https://github.com/leo-project/leofs/issues/239) ``leo_gateway`` Added custom HTTP header for CDN integration
    * [#255](https://github.com/leo-project/leofs/issues/255) ``leo_gateway`` Made a PUT request in parallel when handling a large object
    * [#256](https://github.com/leo-project/leofs/issues/256) ``leo_gateway`` Upgraded [Cowboy 1.0.0](https://github.com/ninenines/cowboy)
    * [#260](https://github.com/leo-project/leofs/issues/260) ``leo_gateway`` Made a MOVE request in parallel when handling a large object
    * ``leo_storage`` ``leo_mq`` Implemented to be able to operate a mq server of a storage internal
    * ``leo_storage`` Able to recursively remove objects of under directory with S3-Clients

Bugs Fixed
-----------

* [#262](https://github.com/leo-project/leofs/issues/262) ``leo_gateway`` ``leo_storage`` Improved RPC in order to be able to handle huge traffic with large size objects
* [#263](https://github.com/leo-project/leofs/issues/263) ``leo_gateway`` Wrong error code when creating a bucket that already exists
* [#265](https://github.com/leo-project/leofs/issues/265) ``leo_object_storage`` Fixed that some succeeded updates might be ignored silently while executing compaction
* [#268](https://github.com/leo-project/leofs/issues/265) ``leo_object_storage`` Fixed that wrong output format of data-diagnosis when including children of an large-object

Used Libraries
---------------

* leo project
    * [leo_backend-db v1.1.3](https://github.com/leo-project/leo_backend_db.git)
    * [leo_cache v0.6.0](https://github.com/leo-project/leo_cache.git)
    * [leo_commons v1.1.0](https://github.com/leo-project/leo_commons.git)
    * [leo_dcerl v0.2.11](https://github.com/leo-project/leo_dcerl.git)
    * [leo_logger v1.1.3](https://github.com/leo-project/leo_logger.git)
    * [leo_mcerl v0.4.1](https://github.com/leo-project/leo_mcerl.git)
    * [leo_mq v1.2.0](https://github.com/leo-project/leo_mq.git)
    * [leo_object_storage v1.1.8](https://github.com/leo-project/leo_object_storage.git)
    * [leo_ordning_reda v0.10.9](https://github.com/leo-project/leo_ordning_reda.git)
    * [leo_redundant_manager 1.9.1](https://github.com/leo-project/leo_redundant_manager.git)
    * [leo_rpc v0.8.10](https://github.com/leo-project/leo_rpc.git)
    * [leo_pod v0.6.2](https://github.com/leo-project/leo_pod.git)
    * [leo_s3_libs v1.1.4](https://github.com/leo-project/leo_s3_libs.git)
    * [leo_statistics v1.0.7](https://github.com/leo-project/leo_statistics.git)
    * [leo_watchdog v0.4.1](https://github.com/leo-project/leo_watchdog.git)
    * [savanna_agent v0.4.4](https://github.com/leo-project/savanna_agent.git)
    * [savanna_commons v0.8.6](https://github.com/leo-project/savanna_commons.git)
    * [erpcgen v0.2.3](https://github.com/leo-project/erpcgen.git)
    * [nfs_rpc_server v0.2.2](https://github.com/leo-project/nfs_rpc_server.git)
    * [leo_gateway v1.2.0](https://github.com/leo-project/leo_gateway.git)
    * [leo_manager v1.2.0](https://github.com/leo-project/leo_manager.git)
    * [leo_storage v1.2.0](https://github.com/leo-project/leo_storage.git)
* others
    * [bitcask v1.7.0](https://github.com/basho/bitcask.git)
    * [cowboy v1.0.0](https://github.com/extend/cowboy.git)
    * [cowlib v1.0.0](https://github.com/extend/cowboy.git)
    * [elarm v0.3.0](https://github.com/leo-project/elarm.git)
    * [eleveldb v1.4.10](https://github.com/basho/eleveldb.git)
    * [folsom v0.8.1](https://github.com/boundary/folsom.git)
    * [jiffy v0.8.5](https://github.com/davisp/jiffy.git)
    * [lz4 v0.2.2](https://github.com/leo-project/erlang-lz4.git) - forked from [szktty/erlang-lz4](https://github.com/szktty/erlng-lz4)


text:
Pattern: Unexpected newline character

Issue: -

## Description

This rule enforces the type of new line characters.

## Configuration

-   Set `type` to `unix` to use UNIX-typed new line characters (`\n`), or `dos` to use DOS-typed new line characters (`\r\n`).

## Further Reading

* [Yamllint - new_lines](https://yamllint.readthedocs.io/en/stable/rules.html#module-yamllint.rules.new_lines)

redpajama_set_name: RedPajamaGithub


text:
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.markdownItAttrs = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
'use strict';

function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }

var patternsConfig = require('./patterns.js');

var defaultOptions = {
  leftDelimiter: '{',
  rightDelimiter: '}',
  allowedAttributes: []
};

module.exports = function attributes(md, options_) {
  var options = Object.assign({}, defaultOptions);
  options = Object.assign(options, options_);
  var patterns = patternsConfig(options);

  function curlyAttrs(state) {
    var tokens = state.tokens;

    var _loop = function _loop(i) {
      for (var p = 0; p < patterns.length; p++) {
        var pattern = patterns[p];
        var j = null; // position of child with offset 0

        var match = pattern.tests.every(function (t) {
          var res = test(tokens, i, t);

          if (res.j !== null) {
            j = res.j;
          }

          return res.match;
        });

        if (match) {
          pattern.transform(tokens, i, j);

          if (pattern.name === 'inline attributes' || pattern.name === 'inline nesting 0') {
            // retry, may be several inline attributes
            p--;
          }
        }
      }
    };

    for (var i = 0; i < tokens.length; i++) {
      _loop(i);
    }
  }

  md.core.ruler.before('linkify', 'curly_attributes', curlyAttrs);
};
/**
 * Test if t matches token stream.
 *
 * @param {array} tokens
 * @param {number} i
 * @param {object} t Test to match.
 * @return {object} { match: true|false, j: null|number }
 */

function test(tokens, i, t) {
  var res = {
    match: false,
    j: null // position of child

  };
  var ii = t.shift !== undefined ? i + t.shift : t.position;

  if (t.shift !== undefined && ii < 0) {
    // we should never shift to negative indexes (rolling around to back of array)
    return res;
  }

  var token = get(tokens, ii); // supports negative ii

  if (token === undefined) {
    return res;
  }

  var _loop2 = function _loop2() {
    var key = _Object$keys[_i];

    if (key === 'shift' || key === 'position') {
      return "continue";
    }

    if (token[key] === undefined) {
      return {
        v: res
      };
    }

    if (key === 'children' && isArrayOfObjects(t.children)) {
      var _ret2 = function () {
        if (token.children.length === 0) {
          return {
            v: {
              v: res
            }
          };
        }

        var match;
        var childTests = t.children;
        var children = token.children;

        if (childTests.every(function (tt) {
          return tt.position !== undefined;
        })) {
          // positions instead of shifts, do not loop all children
          match = childTests.every(function (tt) {
            return test(children, tt.position, tt).match;
          });

          if (match) {
            // we may need position of child in transform
            var j = last(childTests).position;
            res.j = j >= 0 ? j : children.length + j;
          }
        } else {
          var _loop3 = function _loop3(_j) {
            match = childTests.every(function (tt) {
              return test(children, _j, tt).match;
            });

            if (match) {
              res.j = _j; // all tests true, continue with next key of pattern t

              return "break";
            }
          };

          for (var _j = 0; _j < children.length; _j++) {
            var _ret3 = _loop3(_j);

            if (_ret3 === "break") break;
          }
        }

        if (match === false) {
          return {
            v: {
              v: res
            }
          };
        }

        return {
          v: "continue"
        };
      }();

      if (_typeof(_ret2) === "object") return _ret2.v;
    }

    switch (_typeof(t[key])) {
      case 'boolean':
      case 'number':
      case 'string':
        if (token[key] !== t[key]) {
          return {
            v: res
          };
        }

        break;

      case 'function':
        if (!t[key](token[key])) {
          return {
            v: res
          };
        }

        break;

      case 'object':
        if (isArrayOfFunctions(t[key])) {
          var r = t[key].every(function (tt) {
            return tt(token[key]);
          });

          if (r === false) {
            return {
              v: res
            };
          }

          break;
        }

      // fall through for objects !== arrays of functions

      default:
        throw new Error("Unknown type of pattern test (key: ".concat(key, "). Test should be of type boolean, number, string, function or array of functions."));
    }
  };

  for (var _i = 0, _Object$keys = Object.keys(t); _i < _Object$keys.length; _i++) {
    var _ret = _loop2();

    if (_ret === "continue") continue;
    if (_typeof(_ret) === "object") return _ret.v;
  } // no tests returned false -> all tests returns true

  res.match = true;
  return res;
}

function isArrayOfObjects(arr) {
  return Array.isArray(arr) && arr.length && arr.every(function (i) {
    return _typeof(i) === 'object';
  });
}

function isArrayOfFunctions(arr) {
  return Array.isArray(arr) && arr.length && arr.every(function (i) {
    return typeof i === 'function';
  });
}
/**
 * Get n item of array. Supports negative n, where -1 is last
 * element in array.
 * @param {array} arr
 * @param {number} n
 */

function get(arr, n) {
  return n >= 0 ? arr[n] : arr[arr.length + n];
} // get last element of array, safe - returns {} if not found

function last(arr) {
  return arr.slice(-1)[0] || {};
}

},{"./patterns.js":2}],2:[function(require,module,exports){
'use strict';
/**
 * If a pattern matches the token stream,
 * then run transform.
 */

var utils = require('./utils.js');

module.exports = function (options) {
  var __hr = new RegExp('^ {0,3}[-*_]{3,} ?' + utils.escapeRegExp(options.leftDelimiter) + '[^' + utils.escapeRegExp(options.rightDelimiter) + ']');

  return [{
    /**
     * ```python {.cls}
     * for i in range(10):
     *     print(i)
     * ```
     */
    name: 'fenced code blocks',
    tests: [{
      shift: 0,
      block: true,
      info: utils.hasDelimiters('end', options)
    }],
    transform: function transform(tokens, i) {
      var token = tokens[i];
      var start = token.info.lastIndexOf(options.leftDelimiter);
      var attrs = utils.getAttrs(token.info, start, options);
      utils.addAttrs(attrs, token);
      token.info = utils.removeDelimiter(token.info, options);
    }
  }, {
    /**
     * bla `click()`{.c} ![](img.png){.d}
     *
     * differs from 'inline attributes' as it does
     * not have a closing tag (nesting: -1)
     */
    name: 'inline nesting 0',
    tests: [{
      shift: 0,
      type: 'inline',
      children: [{
        shift: -1,
        type: function type(str) {
          return str === 'image' || str === 'code_inline';
        }
      }, {
        shift: 0,
        type: 'text',
        content: utils.hasDelimiters('start', options)
      }]
    }],
    transform: function transform(tokens, i, j) {
      var token = tokens[i].children[j];
      var endChar = token.content.indexOf(options.rightDelimiter);
      var attrToken = tokens[i].children[j - 1];
      var attrs = utils.getAttrs(token.content, 0, options);
      utils.addAttrs(attrs, attrToken);

      if (token.content.length === endChar + options.rightDelimiter.length) {
        tokens[i].children.splice(j, 1);
      } else {
        token.content = token.content.slice(endChar + options.rightDelimiter.length);
      }
    }
  }, {
    /**
     * | h1 |
     * | -- |
     * | c1 |
     *
     * {.c}
     */
    name: 'tables',
    tests: [{
      // let this token be i, such that for-loop continues at
      // next token after tokens.splice
      shift: 0,
      type: 'table_close'
    }, {
      shift: 1,
      type: 'paragraph_open'
    }, {
      shift: 2,
      type: 'inline',
      content: utils.hasDelimiters('only', options)
    }],
    transform: function transform(tokens, i) {
      var token = tokens[i + 2];
      var tableOpen = utils.getMatchingOpeningToken(tokens, i);
      var attrs = utils.getAttrs(token.content, 0, options); // add attributes

      utils.addAttrs(attrs, tableOpen); // remove
{.c}

      tokens.splice(i + 1, 3);
    }
  }, {
    /**
     * *emphasis*{.with attrs=1}
     */
    name: 'inline attributes',
    tests: [{
      shift: 0,
      type: 'inline',
      children: [{
        shift: -1,
        nesting: -1 // closing inline tag, {.a}

      }, {
        shift: 0,
        type: 'text',
        content: utils.hasDelimiters('start', options)
      }]
    }],
    transform: function transform(tokens, i, j) {
      var token = tokens[i].children[j];
      var content = token.content;
      var attrs = utils.getAttrs(content, 0, options);
      var openingToken = utils.getMatchingOpeningToken(tokens[i].children, j - 1);
      utils.addAttrs(attrs, openingToken);
      token.content = content.slice(content.indexOf(options.rightDelimiter) + options.rightDelimiter.length);
    }
  }, {
    /**
     * - item
     * {.a}
     */
    name: 'list softbreak',
    tests: [{
      shift: -2,
      type: 'list_item_open'
    }, {
      shift: 0,
      type: 'inline',
      children: [{
        position: -2,
        type: 'softbreak'
      }, {
        position: -1,
        type: 'text',
        content: utils.hasDelimiters('only', options)
      }]
    }],
    transform: function transform(tokens, i, j) {
      var token = tokens[i].children[j];
      var content = token.content;
      var attrs = utils.getAttrs(content, 0, options);
      var ii = i - 2;

      while (tokens[ii - 1] && tokens[ii - 1].type !== 'ordered_list_open' && tokens[ii - 1].type !== 'bullet_list_open') {
        ii--;
      }

      utils.addAttrs(attrs, tokens[ii - 1]);
      tokens[i].children = tokens[i].children.slice(0, -2);
    }
  }, {
    /**
     * - nested list
     *   - with double \n
     *   {.a} <-- apply to nested ul
     *
     * {.b} <-- apply to root

     */
    name: 'list double softbreak',
    tests: [{
      // let this token be i = 0 so that we can erase
      // the
{.a}
 tokens below
      shift: 0,
      type: function type(str) {
        return str === 'bullet_list_close' || str === 'ordered_list_close';
      }
    }, {
      shift: 1,
      type: 'paragraph_open'
    }, {
      shift: 2,
      type: 'inline',
      content: utils.hasDelimiters('only', options),
      children: function children(arr) {
        return arr.length === 1;
      }
    }, {
      shift: 3,
      type: 'paragraph_close'
    }],
    transform: function transform(tokens, i) {
      var token = tokens[i + 2];
      var content = token.content;
      var attrs = utils.getAttrs(content, 0, options);
      var openingToken = utils.getMatchingOpeningToken(tokens, i);
      utils.addAttrs(attrs, openingToken);
      tokens.splice(i + 1, 3);
    }
  }, {
    /**
     * - end of {.list-item}
     */
    name: 'list item end',
    tests: [{
      shift: -2,
      type: 'list_item_open'
    }, {
      shift: 0,
      type: 'inline',
      children: [{
        position: -1,
        type: 'text',
        content: utils.hasDelimiters('end', options)
      }]
    }],
    transform: function transform(tokens, i, j) {
      var token = tokens[i].children[j];
      var content = token.content;
      var attrs = utils.getAttrs(content, content.lastIndexOf(options.leftDelimiter), options);
      utils.addAttrs(attrs, tokens[i - 2]);
      var trimmed = content.slice(0, content.lastIndexOf(options.leftDelimiter));
      token.content = last(trimmed) !== ' ' ? trimmed : trimmed.slice(0, -1);
    }
  }, {
    /**
     * something with softbreak
     * {.cls}
     */
    name: '\n{.a} softbreak then curly in start',
    tests: [{
      shift: 0,
      type: 'inline',
      children: [{
        position: -2,
        type: 'softbreak'
      }, {
        position: -1,
        type: 'text',
        content: utils.hasDelimiters('only', options)
      }]
    }],
    transform: function transform(tokens, i, j) {
      var token = tokens[i].children[j];
      var attrs = utils.getAttrs(token.content, 0, options); // find last closing tag

      var ii = i + 1;

      while (tokens[ii + 1] && tokens[ii + 1].nesting === -1) {
        ii++;
      }

      var openingToken = utils.getMatchingOpeningToken(tokens, ii);
      utils.addAttrs(attrs, openingToken);
      tokens[i].children = tokens[i].children.slice(0, -2);
    }
  }, {
    /**
     * horizontal rule --- {#id}
     */
    name: 'horizontal rule',
    tests: [{
      shift: 0,
      type: 'paragraph_open'
    }, {
      shift: 1,
      type: 'inline',
      children: function children(arr) {
        return arr.length === 1;
      },
      content: function content(str) {
        return str.match(__hr) !== null;
      }
    }, {
      shift: 2,
      type: 'paragraph_close'
    }],
    transform: function transform(tokens, i) {
      var token = tokens[i];
      token.type = 'hr';
      token.tag = 'hr';
      token.nesting = 0;
      var content = tokens[i + 1].content;
      var start = content.lastIndexOf(options.leftDelimiter);
      var attrs = utils.getAttrs(content, start, options);
      utils.addAttrs(attrs, token);
      token.markup = content;
      tokens.splice(i + 1, 2);
    }
  }, {
    /**
     * end of {.block}
     */
    name: 'end of block',
    tests: [{
      shift: 0,
      type: 'inline',
      children: [{
        position: -1,
        content: utils.hasDelimiters('end', options),
        type: function type(t) {
          return t !== 'code_inline' && t !== 'math_inline';
        }
      }]
    }],
    transform: function transform(tokens, i, j) {
      var token = tokens[i].children[j];
      var content = token.content;
      var attrs = utils.getAttrs(content, content.lastIndexOf(options.leftDelimiter), options);
      var ii = i + 1;

      while (tokens[ii + 1] && tokens[ii + 1].nesting === -1) {
        ii++;
      }

      var openingToken = utils.getMatchingOpeningToken(tokens, ii);
      utils.addAttrs(attrs, openingToken);
      var trimmed = content.slice(0, content.lastIndexOf(options.leftDelimiter));
      token.content = last(trimmed) !== ' ' ? trimmed : trimmed.slice(0, -1);
    }
  }];
}; // get last element of array or string

function last(arr) {
  return arr.slice(-1)[0];
}

},{"./utils.js":3}],3:[function(require,module,exports){
"use strict";

/**
 * parse {.class #id key=val} strings
 * @param {string} str: string to parse
 * @param {int} start: where to start parsing (including {)
 * @returns {2d array}: [['key', 'val'], ['class', 'red']]
 */
exports.getAttrs = function (str, start, options) {
  // not tab, line feed, form feed, space, solidus, greater than sign, quotation mark, apostrophe and equals sign
  var allowedKeyChars = /[^\t\n\f />"'=]/;
  var pairSeparator = ' ';
  var keySeparator = '=';
  var classChar = '.';
  var idChar = '#';
  var attrs = [];
  var key = '';
  var value = '';
  var parsingKey = true;
  var valueInsideQuotes = false; // read inside {}
  // start + left delimiter length to avoid beginning {
  // breaks when } is found or end of string

  for (var i = start + options.leftDelimiter.length; i < str.length; i++) {
    if (str.slice(i, i + options.rightDelimiter.length) === options.rightDelimiter) {
      if (key !== '') {
        attrs.push([key, value]);
      }

      break;
    }

    var char_ = str.charAt(i); // switch to reading value if equal sign

    if (char_ === keySeparator && parsingKey) {
      parsingKey = false;
      continue;
    } // {.class} {..css-module}

    if (char_ === classChar && key === '') {
      if (str.charAt(i + 1) === classChar) {
        key = 'css-module';
        i += 1;
      } else {
        key = 'class';
      }

      parsingKey = false;
      continue;
    } // {#id}

    if (char_ === idChar && key === '') {
      key = 'id';
      parsingKey = false;
      continue;
    } // {value="inside quotes"}

    if (char_ === '"' && value === '') {
      valueInsideQuotes = true;
      continue;
    }

    if (char_ === '"' && valueInsideQuotes) {
      valueInsideQuotes = false;
      continue;
    } // read next key/value pair

    if (char_ === pairSeparator && !valueInsideQuotes) {
      if (key === '') {
        // beginning or ending space: { .red } vs {.red}
        continue;
      }

      attrs.push([key, value]);
      key = '';
      value = '';
      parsingKey = true;
      continue;
    } // continue if character not allowed

    if (parsingKey && char_.search(allowedKeyChars) === -1) {
      continue;
    } // no other conditions met; append to key/value

    if (parsingKey) {
      key += char_;
      continue;
    }

    value += char_;
  }

  if (options.allowedAttributes && options.allowedAttributes.length) {
    var allowedAttributes = options.allowedAttributes;
    return attrs.filter(function (attrPair) {
      var attr = attrPair[0];

      function isAllowedAttribute(allowedAttribute) {
        return attr === allowedAttribute || allowedAttribute instanceof RegExp && allowedAttribute.test(attr);
      }

      return allowedAttributes.some(isAllowedAttribute);
    });
  }

  return attrs;
};
/**
 * add attributes from [['key', 'val']] list
 * @param {array} attrs: [['key', 'val']]
 * @param {token} token: which token to add attributes
 * @returns token
 */

exports.addAttrs = function (attrs, token) {
  for (var j = 0, l = attrs.length; j < l; ++j) {
    var key = attrs[j][0];

    if (key === 'class') {
      token.attrJoin('class', attrs[j][1]);
    } else if (key === 'css-module') {
      token.attrJoin('css-module', attrs[j][1]);
    } else {
      token.attrPush(attrs[j]);
    }
  }

  return token;
};
/**
 * Does string have properly formatted curly?
 *
 * start: '{.a} asdf'
 * end: 'asdf {.a}'
 * only: '{.a}'
 *
 * @param {string} where to expect {} curly. start, end or only.
 * @return {function(string)} Function which testes if string has curly.
 */

exports.hasDelimiters = function (where, options) {
  if (!where) {
    throw new Error('Parameter `where` not passed. Should be "start", "end" or "only".');
  }
  /**
   * @param {string} str
   * @return {boolean}
   */

  return function (str) {
    // we need minimum three chars, for example {b}
    var minCurlyLength = options.leftDelimiter.length + 1 + options.rightDelimiter.length;

    if (!str || typeof str !== 'string' || str.length < minCurlyLength) {
      return false;
    }

    function validCurlyLength(curly) {
      var isClass = curly.charAt(options.leftDelimiter.length) === '.';
      var isId = curly.charAt(options.leftDelimiter.length) === '#';
      return isClass || isId ? curly.length >= minCurlyLength + 1 : curly.length >= minCurlyLength;
    }

    var start, end, slice, nextChar;
    var rightDelimiterMinimumShift = minCurlyLength - options.rightDelimiter.length;

    switch (where) {
      case 'start':
        // first char should be {, } found in char 2 or more
        slice = str.slice(0, options.leftDelimiter.length);
        start = slice === options.leftDelimiter ? 0 : -1;
        end = start === -1 ? -1 : str.indexOf(options.rightDelimiter, rightDelimiterMinimumShift); // check if next character is not one of the delimiters

        nextChar = str.charAt(end + options.rightDelimiter.length);

        if (nextChar && options.rightDelimiter.indexOf(nextChar) !== -1) {
          end = -1;
        }

        break;

      case 'end':
        // last char should be }
        start = str.lastIndexOf(options.leftDelimiter);
        end = start === -1 ? -1 : str.indexOf(options.rightDelimiter, start + rightDelimiterMinimumShift);
        end = end === str.length - options.rightDelimiter.length ? end : -1;
        break;

      case 'only':
        // '{.a}'
        slice = str.slice(0, options.leftDelimiter.length);
        start = slice === options.leftDelimiter ? 0 : -1;
        slice = str.slice(str.length - options.rightDelimiter.length);
        end = slice === options.rightDelimiter ? str.length - options.rightDelimiter.length : -1;
        break;

      default:
        throw new Error("Unexpected case ".concat(where, ", expected 'start', 'end' or 'only'"));
    }

    return start !== -1 && end !== -1 && validCurlyLength(str.substring(start, end + options.rightDelimiter.length));
  };
};
/**
 * Removes last curly from string.
 */

exports.removeDelimiter = function (str, options) {
  var start = escapeRegExp(options.leftDelimiter);
  var end = escapeRegExp(options.rightDelimiter);
  var curly = new RegExp('[ \\n]?' + start + '[^' + start + end + ']+' + end + '$');
  var pos = str.search(curly);
  return pos !== -1 ? str.slice(0, pos) : str;
};
/**
 * Escapes special characters in string s such that the string
 * can be used in `new RegExp`. For example "[" becomes "\\[".
 *
 * @param {string} s Regex string.
 * @return {string} Escaped string.
 */

function escapeRegExp(s) {
  return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
}

exports.escapeRegExp = escapeRegExp;
/**
 * find corresponding opening block
 */

exports.getMatchingOpeningToken = function (tokens, i) {
  if (tokens[i].type === 'softbreak') {
    return false;
  } // non closing blocks, example img

  if (tokens[i].nesting === 0) {
    return tokens[i];
  }

  var level = tokens[i].level;
  var type = tokens[i].type.replace('_close', '_open');

  for (; i >= 0; --i) {
    if (tokens[i].type === type && tokens[i].level === level) {
      return tokens[i];
    }
  }

  return false;
};
/**
 * from https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.js
 */

var HTML_ESCAPE_TEST_RE = /[&<>"]/;
var HTML_ESCAPE_REPLACE_RE = /[&<>"]/g;
var HTML_REPLACEMENTS = {
  '&': '&',
  '<': '<',
  '>': '>',
  '"': '"'
};

function replaceUnsafeChar(ch) {
  return HTML_REPLACEMENTS[ch];
}

exports.escapeHtml = function (str) {
  if (HTML_ESCAPE_TEST_RE.test(str)) {
    return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar);
  }

  return str;
};

},{}]},{},[1])(1)
});


text:
require "spec_helper"

describe EveOnline::ESI::Models::Group do
  it { should be_a(EveOnline::ESI::Models::Base) }

  let(:options) { double }

  subject { described_class.new(options) }

  describe "#initialize" do
    its(:options) { should eq(options) }
  end

  describe "#as_json" do
    let(:group) { described_class.new(options) }

    before { expect(group).to receive(:category_id).and_return(25) }

    before { expect(group).to receive(:group_id).and_return(450) }

    before { expect(group).to receive(:name).and_return("Arkonor") }

    before { expect(group).to receive(:published).and_return(true) }

    subject { group.as_json }

    its([:category_id]) { should eq(25) }

    its([:group_id]) { should eq(450) }

    its([:name]) { should eq("Arkonor") }

    its([:published]) { should eq(true) }
  end

  describe "#category_id" do
    before { expect(options).to receive(:[]).with("category_id") }

    specify { expect { subject.category_id }.not_to raise_error }
  end

  describe "#group_id" do
    before { expect(options).to receive(:[]).with("group_id") }

    specify { expect { subject.group_id }.not_to raise_error }
  end

  describe "#name" do
    before { expect(options).to receive(:[]).with("name") }

    specify { expect { subject.name }.not_to raise_error }
  end

  describe "#published" do
    before { expect(options).to receive(:[]).with("published") }

    specify { expect { subject.published }.not_to raise_error }
  end

  describe "#type_ids" do
    before { expect(options).to receive(:[]).with("types") }

    specify { expect { subject.type_ids }.not_to raise_error }
  end
end


text:
<?xml version="1.0" encoding="UTF-8"?>
<!--
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
-->
<forms xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://ofbiz.apache.org/Widget-Form" xsi:schemaLocation="http://ofbiz.apache.org/Widget-Form http://ofbiz.apache.org/dtds/widget-form.xsd">

    <form name="ListTimesheets" type="list" list-name="timesheets" paginate-target="MyWork"
        odd-row-style="alternate-row" default-table-style="basic-table hover-bar">
        <actions>
            <set field="complete" value="${uiLabelMap.ScrumToComplete}"/>
        </actions>
        <field name="timesheetId" title="${uiLabelMap.WorkEffortTimesheetTimesheetId}" widget-style="buttontext">
            <hyperlink description="${timesheetId}" target="MyWork" also-hidden="false">
                <parameter param-name="timesheetId"/>
            </hyperlink>
        </field>
        <field name="statusId"><display-entity entity-name="StatusItem"/></field>
        <field name="fromDate" title="${uiLabelMap.CommonFromDate}"><display type="date"/></field>
        <field name="thruDate" title="${uiLabelMap.CommonThruDate}"><display type="date"/></field>
        <field name="hours"><display/></field>
        <field name="comments" title="${uiLabelMap.CommonComments}"><display/></field>
        <field name="completeLink" title="${uiLabelMap.CommonStatustoComplete}" widget-style="buttontext">
            <hyperlink description="${groovy:statusId.equals("TIMESHEET_IN_PROCESS")?complete:""}" target="${my}TimeSheetStatusToComplete" also-hidden="false">
                <parameter param-name="timesheetId"/>
                <parameter param-name="statusId" value="TIMESHEET_COMPLETED"/>
            </hyperlink>
        </field>
    </form>

    <form name="WeekTimesheet" type="list" list-name="timeEntries" separate-columns="true" paginate-target="MyWork" paginate-index-field="WeekTimesheet_index" paginate-size-field="WeekTimesheet_size"
        odd-row-style="alternate-row" default-table-style="basic-table hover-bar">
        <row-actions>
            <service service-name="getProjectInfoFromTask" result-map="result">
                <field-map field-name="taskId" from-field="workEffortId"/>
            </service>
            <entity-and entity-name="EmplLeave" list="emplLeaveList">
                <field-map field-name="partyId" from-field="partyId"/>
                <field-map field-name="leaveTypeId" from-field="leaveTypeId"/>
                <field-map field-name="fromDate" from-field="leavefromDate"/>
            </entity-and>
            <set field="taskId" value="${emplLeaveList[0].leaveTypeId}" default-value="${result.taskId}"></set>
            <set field="emplLeaveMap" from-field="emplLeaveList[0]"/>
            <set field="custRequestId" from-field="result.backlogId"/>
        </row-actions>
        <field name="timesheetId"><hidden/></field>
        <field name="taskWbsId"><hidden/></field>
        <field name="taskId" use-when="emplLeaveMap!=null"><hidden/> </field>
        <field name="taskId" use-when="emplLeaveMap==null"><hidden value="${workEffortId}"/></field>
        <field name="workEffortName" title="${uiLabelMap.ScrumTaskName}" use-when="emplLeaveMap!=null||emplLeaveMap!=""">
            <display description="${emplLeaveList[0].description}"/>
        </field>
        <field name="workEffortName" title="${uiLabelMap.ScrumTaskName}" use-when="emplLeaveMap==null||emplLeaveMap==""">
            <display-entity entity-name="WorkEffort" description="${workEffortName}" key-field-name="workEffortId">
                <sub-hyperlink target="taskView" description=" [${workEffortId}]">
                    <parameter param-name="taskId" from-field="workEffortId"/>
                </sub-hyperlink>
            </display-entity>
        </field>
        <field name="backlogName" entry-name="custRequestId" title="${uiLabelMap.ScrumProductBacklogName}" use-when="custRequestId!=null">
            <display-entity entity-name="CustRequest" description="${result.backlogName}" key-field-name="custRequestId">
                <sub-hyperlink target="ViewProdBacklogItem" description=" [${result.backlogId}]">
                    <parameter param-name="custRequestId" from-field="result.backlogId"/>
                </sub-hyperlink>
            </display-entity>
        </field>
        <field name="sprintName" ><display description="${result.sprintName}"></display> </field>
        <field name="projectName" title="${uiLabelMap.ScrumProjectName}">
            <hyperlink target="viewScrumProject"  description="${projectName}">
                <parameter param-name="projectId"/>
            </hyperlink>
        </field>
        <field name="checkComplete" title="${uiLabelMap.ScrumCheckComplete}"><display/></field>
        <field name="rateTypeId" title="${uiLabelMap.ScrumRateTypeId}"><display-entity entity-name="RateType"/></field>
        <field name="planHours" title="${uiLabelMap.ScrumPlanHours}"><display/></field>
        <field name="d0" parameter-name="hoursDay0" title="${uiLabelMap.ScrumMon}"><display/></field>
        <field name="d1" parameter-name="hoursDay1" title="${uiLabelMap.ScrumTue}"><display/></field>
        <field name="d2" parameter-name="hoursDay2" title="${uiLabelMap.ScrumWen}"><display/></field>
        <field name="d3" parameter-name="hoursDay3" title="${uiLabelMap.ScrumThu}"><display/></field>
        <field name="d4" parameter-name="hoursDay4" title="${uiLabelMap.ScrumFri}"><display/></field>
        <field name="d5" parameter-name="hoursDay5" title="${uiLabelMap.ScrumSat}"><display/></field>
        <field name="d6" parameter-name="hoursDay6" title="${uiLabelMap.ScrumSun}"><display/></field>
        <field name="actualHours" title="${uiLabelMap.ScrumActualHours}"><display/></field>
    </form>

    <form name="EditWeekTimesheet" type="multi" list-name="timeEntries" use-row-submit="true" paginate-target="MyWork" paginate-index-field="EditWeekTimeshee_index" paginate-size-field="EditWeekTimeshee_size"
        separate-columns="true" target="update${my}Timesheet?${url}" odd-row-style="alternate-row" default-table-style="basic-table hover-bar" >
        <row-actions>
            <service service-name="getProjectInfoFromTask" result-map="result">
                <field-map field-name="taskId" from-field="workEffortId"/>
            </service>
            <entity-and entity-name="CustRequestWorkEffort" list="custRequestList">
                <field-map field-name="workEffortId" from-field="workEffortId"/>
            </entity-and>
            <entity-and entity-name="CustRequest" list="custRequest">
                <field-map field-name="custRequestId" from-field="custRequestList[0].custRequestId"/>
                <field-map field-name="custRequestTypeId" value="RF_UNPLAN_BACKLOG"/>
            </entity-and>
            <entity-and entity-name="CustRequestItem" list="productList">
                <field-map field-name="custRequestId" from-field="custRequest[0].custRequestId"/>
            </entity-and>
            <entity-one entity-name="Product" value-field="product">
                <field-map field-name="productId" from-field="productList[0].productId"/>
            </entity-one>
            <entity-and entity-name="EmplLeave" list="emplLeaveList">
                <field-map field-name="partyId" from-field="partyId"/>
                <field-map field-name="leaveTypeId" from-field="leaveTypeId"/>
                <field-map field-name="fromDate" from-field="leavefromDate"/>
            </entity-and >
            <set field="taskId" value="${emplLeaveList[0].leaveTypeId}" default-value="${result.taskId}"></set>
        </row-actions>
        <field name="timesheetId"><hidden/></field>
        <field name="roleTypeId"><hidden/></field>
        <field name="fromDate"><hidden/></field>
        <field name="webSiteId"><hidden value="${webSiteId}"/></field>
        <field name="taskId" title="${uiLabelMap.ScrumTaskName}" parameter-name="workEffortId" encode-output="true">
            <drop-down allow-empty="true" current-description="${result.projectId} ${product.productId} - ${result.projectName}${product.internalName} - ${result.sprintName} - ${groovy:result.backlogName.toString().substring(0,Math.min(result.backlogName.toString().length(),30))}[${result.backlogId}] - ${groovy:result.taskName.toString().substring(0,Math.min(result.taskName.toString().length(),30))}[${result.taskId}]">
                <list-options key-name="taskId" list-name="taskListDropdown" description="${projectId}${productId} - ${projectName} ${productName} - ${sprintName} - ${groovy: if (description) description.substring(0,Math.min(description.length(),30))} [${custRequestId}] - ${groovy:taskName.substring(0,Math.min(taskName.length(),20))}[${taskId}]"/>
                <entity-options entity-name="EmplLeaveType" key-field-name="leaveTypeId"/>
                <sub-hyperlink target="taskView" description="${workEffortId}">
                    <parameter param-name="taskId" from-field="workEffortId"/>
                </sub-hyperlink>
            </drop-down>
        </field>
        <field name="checkComplete" title="${uiLabelMap.ScrumCheckComplete}"><check/></field>
        <field name="rateTypeId" title="${uiLabelMap.ScrumRateTypeId}">
            <drop-down allow-empty="false" no-current-selected-key="${defaultRateTypeId}">
                <entity-options entity-name="RateType"/>
            </drop-down>
        </field>
        <field name="planHours" title="${uiLabelMap.ScrumPlanHrs}"><text size="2"/></field>
        <field name="pl0" parameter-name="planHoursDay0" title="${uiLabelMap.ScrumPlhrs}"><hidden/></field>
        <field name="d0" parameter-name="hoursDay0" title="${uiLabelMap.ScrumMon}"><text size="2"/></field>
        <field name="pd1" parameter-name="planHoursDay1" title="${uiLabelMap.ScrumPlhrs}"><hidden/></field>
        <field name="d1" parameter-name="hoursDay1" title="${uiLabelMap.ScrumTue}"><text size="2"/></field>
        <field name="pd2" parameter-name="planHoursDay2" title="${uiLabelMap.ScrumPlhrs}"><hidden/></field>
        <field name="d2" parameter-name="hoursDay2" title="${uiLabelMap.ScrumWen}"><text size="2"/></field>
        <field name="pd3" parameter-name="planHoursDay3" title="${uiLabelMap.ScrumPlhrs}"><hidden/></field>
        <field name="d3" parameter-name="hoursDay3" title="${uiLabelMap.ScrumThu}"><text size="2"/></field>
        <field name="pd4" parameter-name="planHoursDay4" title="${uiLabelMap.ScrumPlhrs}"><hidden/></field>
        <field name="d4" parameter-name="hoursDay4" title="${uiLabelMap.ScrumFri}"><text size="2"/></field>
        <field name="pd5" parameter-name="planHoursDay5" title="${uiLabelMap.ScrumPlhrs}"><hidden/></field>
        <field name="d5" parameter-name="hoursDay5" title="${uiLabelMap.ScrumSat}" title-style="alert"><text size="2"/></field>
        <field name="pd6" parameter-name="planHoursDay6" title="${uiLabelMap.ScrumPlhrs}"><hidden/></field>
        <field name="d6" parameter-name="hoursDay6" title="${uiLabelMap.ScrumSun}" title-style="alert"><text size="2"/></field>
        <field name="acualTotal" title="${uiLabelMap.ScrumActualHours}"><display/></field>
        <field name="actualHours" title="${uiLabelMap.ScrumActualTotal}"><display/></field>
        <field name="updateButton"><submit button-type="button"/></field>
        <field name="_rowSubmit" title="${uiLabelMap.ScrumRowSubmit}"><hidden value="Y"/></field>
    </form>
</forms>


text:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;

using Internal.NativeFormat;
using Internal.Text;
using Internal.TypeSystem;

namespace ILCompiler.DependencyAnalysis
{
    /// <summary>
    /// Represents a hash table of array types generated into the image.
    /// </summary>
    internal sealed class ArrayMapNode : ObjectNode, ISymbolDefinitionNode
    {
        private ObjectAndOffsetSymbolNode _endSymbol;
        private ExternalReferencesTableNode _externalReferences;

        public ArrayMapNode(ExternalReferencesTableNode externalReferences)
        {
            _endSymbol = new ObjectAndOffsetSymbolNode(this, 0, "__array_type_map_End", true);
            _externalReferences = externalReferences;
        }

        public ISymbolDefinitionNode EndSymbol => _endSymbol;

        public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
        {
            sb.Append(nameMangler.CompilationUnitPrefix).Append("__array_type_map");
        }
        public int Offset => 0;
        public override bool IsShareable => false;

        public override ObjectNodeSection Section => _externalReferences.Section;

        public override bool StaticDependenciesAreComputed => true;

        protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);

        public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
        {
            // This node does not trigger generation of other nodes.
            if (relocsOnly)
                return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });

            var writer = new NativeWriter();
            var typeMapHashTable = new VertexHashtable();

            Section hashTableSection = writer.NewSection();
            hashTableSection.Place(typeMapHashTable);

            foreach (var type in factory.MetadataManager.GetTypesWithConstructedEETypes())
            {
                if (!type.IsSzArray)
                    continue;

                var arrayType = (ArrayType)type;

                if (!arrayType.ElementType.IsValueType)
                    continue;

                // Look at the constructed type symbol. If a constructed type wasn't emitted, then the array map entry isn't valid for use
                IEETypeNode arrayTypeSymbol = factory.ConstructedTypeSymbol(arrayType);

                Vertex vertex = writer.GetUnsignedConstant(_externalReferences.GetIndex(arrayTypeSymbol));

                int hashCode = arrayType.GetHashCode();
                typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
            }

            byte[] hashTableBytes = writer.Save();

            _endSymbol.SetSymbolOffset(hashTableBytes.Length);

            return new ObjectData(hashTableBytes, Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this, _endSymbol });
        }

        protected internal override int Phase => (int)ObjectNodePhase.Ordered;
        public override int ClassCode => (int)ObjectNodeOrder.ArrayMapNode;
    }
}


text:
module LeccaClient
  module Proposal
    class Builder < Hashie::Dash
      include Hashie::Extensions::Dash::Coercion

      property :operacao, coerce: Operation, required: true
      property :cliente, coerce: Customer, required: true
      property :endereco, coerce: Address, required: true
      property :telefone, coerce: Phone, required: true
      property :emprego, coerce: Job, required: true
      property :conta_bancaria, coerce: BankAccount , required: true
      property :fundo, coerce: Fund, required: true

      def line
        [operacao, cliente, endereco, telefone, emprego, conta_bancaria, fundo].map(&:build).reduce(:+)
      end

      def upload
        LeccaClient::Uploader.new(line, filename).upload
      end

      private

      def filename
        file = operacao[:numero_operacao]

        "#{file}.txt"
      end
    end
  end
end