run_length_encoding_rb 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 79d5976a4c25210fa4e2ac722b4d25f8e8d69d28527cad8ac38965f35aa97026
4
+ data.tar.gz: 8b5547077da37fb7ba5870b37783b1d30ae2eb0d6fa949bb0bd1d82e38b0dd0b
5
+ SHA512:
6
+ metadata.gz: 9343ec73fa5899b7af382825918bac63e2357a15f05707750a22061d85f7b3a62a54070e5bc4114c0cdc1d7d0da7c764ce525de5162405cc6f46ca02ef3eac29
7
+ data.tar.gz: e5f1be41e8af7f2528b542a623a134983a447a4b0ff9dadf411951c83f917458f633f2b92f6958f1e0f34a6803cc47b21be1d78539d214189b39aa4af069ace0
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ Style/StringLiterals:
2
+ Enabled: true
3
+ EnforcedStyle: double_quotes
4
+
5
+ Style/StringLiteralsInInterpolation:
6
+ Enabled: true
7
+ EnforcedStyle: double_quotes
8
+
9
+ Layout/LineLength:
10
+ Max: 120
11
+
12
+ Metrics/MethodLength:
13
+ Max: 25
data/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ ### 0.2.1 / 2023-01-25
2
+
3
+ * Updated docs.
4
+
5
+ ### 0.2.0 / 2023-01-25
6
+
7
+ * Improvements:
8
+ * Decoding is implemented now;
9
+ * Code was refactored;
10
+ * Changed gem's name to pass RubyGems.org name filter;
11
+ * Now gem is available at RubyGems.org.
12
+
13
+ ### 0.1.0 / 2022-12-15
14
+
15
+ * Initial release:
16
+ * Only encoding is implemented yet.
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in run_length_encoding.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rubocop", "~> 0.80"
data/Gemfile.lock ADDED
@@ -0,0 +1,40 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ run_length_encoding_rb (0.2.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ parallel (1.22.1)
11
+ parser (3.1.3.0)
12
+ ast (~> 2.4.1)
13
+ rainbow (3.1.1)
14
+ rake (13.0.6)
15
+ regexp_parser (2.6.1)
16
+ rexml (3.2.5)
17
+ rubocop (0.93.1)
18
+ parallel (~> 1.10)
19
+ parser (>= 2.7.1.5)
20
+ rainbow (>= 2.2.2, < 4.0)
21
+ regexp_parser (>= 1.8)
22
+ rexml
23
+ rubocop-ast (>= 0.6.0)
24
+ ruby-progressbar (~> 1.7)
25
+ unicode-display_width (>= 1.4.0, < 2.0)
26
+ rubocop-ast (1.24.0)
27
+ parser (>= 3.1.1.0)
28
+ ruby-progressbar (1.11.0)
29
+ unicode-display_width (1.8.0)
30
+
31
+ PLATFORMS
32
+ x86_64-linux
33
+
34
+ DEPENDENCIES
35
+ rake (~> 13.0)
36
+ rubocop (~> 0.80)
37
+ run_length_encoding_rb!
38
+
39
+ BUNDLED WITH
40
+ 2.2.3
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Mate
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,129 @@
1
+ ## Description
2
+
3
+ A simple gem that does run-length encoding.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'run_length_encoding_rb'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install run_length_encoding_rb
20
+
21
+ ## Usage
22
+
23
+ ### Encoding
24
+
25
+ obj.encode(data [, separator]) -> array
26
+
27
+ #### Arguments
28
+
29
+ + _data_
30
+
31
+ Data to encode. Supported types:
32
+ - Array;
33
+ - String;
34
+ - Enumerator.
35
+
36
+ + _separator_
37
+
38
+ A String or Regexp to split the string into single elements. Used only if _data_ is a String.
39
+
40
+ #### Returns
41
+
42
+ + _Array<Hash{:chunk => Object, :count => Integer}>_
43
+
44
+ Encoded data in the following format:
45
+ Array<Hash{:chunk => Object, :count => Integer}>, where:
46
+ - :chunk => Object: a repeated element;
47
+ - :count => Integer: how many times the element is repeated.
48
+
49
+ ### Encoding examples
50
+
51
+ ```ruby
52
+ require 'run_length_encoding'
53
+
54
+ rle = RunLengthEncoding.new
55
+
56
+ # Encode an array:
57
+ a = %w[foo foo bar foo foo foo]
58
+
59
+ rle.encode(a)
60
+ # => [{:chunk=>"foo", :count=>2}, {:chunk=>"bar", :count=>1}, {:chunk=>"foo", :count=>3}]
61
+
62
+ # Encode a string with a default separator (each character is treated as a single element):
63
+ str = 'foo'
64
+ rle.encode(str)
65
+ # => [{:chunk=>"f", :count=>1}, {:chunk=>"o", :count=>2}]
66
+
67
+ # Encode a string with a custom separator:
68
+ str = 'foo_foo_bar'
69
+ rle.encode(str, '_')
70
+ # => [{:chunk=>"foo", :count=>2}, {:chunk=>"bar", :count=>1}]
71
+
72
+ # Encode an enumerator:
73
+ str = 'foo'
74
+ rle.encode(str.each_byte)
75
+ # => [{:chunk=>102, :count=>1}, {:chunk=>111, :count=>2}]
76
+ ```
77
+
78
+ ### Decoding
79
+
80
+ obj.decode(data) -> array
81
+
82
+ #### Arguments
83
+
84
+ + _data_
85
+
86
+ Data to decode in the following format:
87
+ Array<Hash{:chunk => Object, :count => Integer}>, where:
88
+ - :chunk => Object: a repeated element;
89
+ + :count => Integer: how many times the element is repeated.
90
+
91
+ #### Returns
92
+
93
+ Array<Object>
94
+
95
+ Decoded data.
96
+ <!-- -->
97
+
98
+ ### Decoding example
99
+
100
+ ```ruby
101
+ require 'run_length_encoding'
102
+
103
+ rle = RunLengthEncoding.new
104
+
105
+ # Decode data of mixed types:
106
+ data = [
107
+ { count: 3, chunk: "foo" },
108
+ { count: 1, chunk: "bar" },
109
+ { count: 2, chunk: nil },
110
+ { count: 4, chunk: 1 }
111
+ ]
112
+
113
+ rle.decode(data)
114
+ # => ["foo", "foo", "foo", "bar", nil, nil, 1, 1, 1, 1]
115
+ ```
116
+
117
+ ## Development
118
+
119
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
120
+
121
+ You can also run `bin/console` for an interactive prompt that will allow you to experiment.
122
+
123
+ ## Contributing
124
+
125
+ Bug reports and pull requests are welcome on GitHub at https://github.com/8bit-mate/run_length_encoding.
126
+
127
+ ## License
128
+
129
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rubocop/rake_task"
5
+
6
+ RuboCop::RakeTask.new
7
+
8
+ task default: :rubocop
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "run_length_encoding"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Constants
4
+ CHUNK_KEY = :chunk
5
+ COUNT_KEY = :count
6
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "decoding_element_check"
4
+ require_relative "constants"
5
+
6
+ #
7
+ # Decode run-length encoded data.
8
+ #
9
+ module Decoder
10
+ include Constants
11
+ include DecodingElementCheck
12
+
13
+ #
14
+ # Pass data to the decoder.
15
+ #
16
+ # @param [Array<Hash{ Symbol => Object }>] data
17
+ #
18
+ # @return [Array]
19
+ #
20
+ # @raise [ArgumentError, TypeError]
21
+ # Raises if data isn't an Array [TypeError] or an empty Array [ArgumentError].
22
+ #
23
+ def decode(data)
24
+ ex_details = _check_dec_data(data)
25
+
26
+ raise(ex_details[:ex_type], ex_details[:ex_msg]) if ex_details
27
+
28
+ _decode(data)
29
+ end
30
+
31
+ private
32
+
33
+ def _check_dec_data(data)
34
+ case data
35
+ when Array
36
+ if data.to_a.empty?
37
+ {
38
+ ex_type: ArgumentError,
39
+ ex_msg: "the given data is empty (no data to decode)"
40
+ }
41
+ end
42
+ else
43
+ {
44
+ ex_type: TypeError,
45
+ ex_msg: "wrong argument type #{data.class} (expected Array)"
46
+ }
47
+ end
48
+ end
49
+
50
+ #
51
+ # Decode data.
52
+ #
53
+ # @param [Array<Hash{ Symbol => Object }>] data
54
+ #
55
+ # @return [Array]
56
+ #
57
+ # @raise [ArgumentError, TypeError]
58
+ #
59
+ def _decode(data)
60
+ decoded_data = []
61
+
62
+ data.each do |hash|
63
+ check_result = _valid_hash?(hash)
64
+ raise(check_result[:ex_type], check_result[:ex_msg]) unless check_result[:comply]
65
+
66
+ hash[COUNT_KEY].times { decoded_data.append(hash[CHUNK_KEY]) }
67
+ end
68
+
69
+ decoded_data
70
+ end
71
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "constants"
4
+
5
+ #
6
+ # Set of checks of a single element to decode.
7
+ #
8
+ module DecodingElementCheck
9
+ include Constants
10
+
11
+ private
12
+
13
+ #
14
+ # Check if element obj complies with the following requirements:
15
+ # 1. is a hash;
16
+ # 2. has keys:
17
+ # - Constants::CHUNK_KEY (repeating element),
18
+ # - Constants::COUNT_KEY (how many times element is repeating);
19
+ # 3. COUNT_KEY's value is an Integer;
20
+ # 4. COUNT_KEY's value is a positive number.
21
+ #
22
+ # @param [Object] obj
23
+ # Object to check.
24
+ #
25
+ # @return [Hash{ Symbol => Object }] result
26
+ # Result of checks.
27
+ # If all checks are passed:
28
+ # result = { comply: true }
29
+ #
30
+ # If a check is failed, result also contains exception type and exception message:
31
+ # result = { comply: false, ex_type: Exception, ex_msg: String }
32
+ #
33
+ def _valid_hash?(obj)
34
+ check_list = [
35
+ method(:_a_hash?),
36
+ method(:_valid_keys?),
37
+ method(:_count_is_integer?),
38
+ method(:_count_is_positive?)
39
+ ]
40
+
41
+ for method in check_list
42
+ result = method.call(obj)
43
+ break unless result[:comply]
44
+ end
45
+
46
+ result
47
+ end
48
+
49
+ # Check if obj is a hash.
50
+ def _a_hash?(obj)
51
+ if obj.is_a?(Hash)
52
+ {
53
+ comply: true
54
+ }
55
+ else
56
+ {
57
+ ex_type: TypeError,
58
+ ex_msg: "wrong argument type #{obj.class} (expected Hash)",
59
+ comply: false
60
+ }
61
+ end
62
+ end
63
+
64
+ # Check if hash has valid keys.
65
+ def _valid_keys?(hash)
66
+ if hash.key?(CHUNK_KEY) && hash.key?(COUNT_KEY)
67
+ {
68
+ comply: true
69
+ }
70
+ else
71
+ {
72
+ ex_type: ArgumentError,
73
+ ex_msg: "hash #{hash} has wrong keys (key is missing or has a wrong name)",
74
+ comply: false
75
+ }
76
+ end
77
+ end
78
+
79
+ # Check if count is an Integer.
80
+ def _count_is_integer?(hash)
81
+ if hash[COUNT_KEY].is_a?(Integer)
82
+ {
83
+ comply: true
84
+ }
85
+ else
86
+ {
87
+ ex_type: TypeError,
88
+ ex_msg: "wrong argument type #{hash[COUNT_KEY].class} (expected Integer)",
89
+ comply: false
90
+ }
91
+ end
92
+ end
93
+
94
+ # Check if count is a positive number.
95
+ def _count_is_positive?(hash)
96
+ if hash[COUNT_KEY].positive?
97
+ {
98
+ comply: true
99
+ }
100
+ else
101
+ {
102
+ ex_type: ArgumentError,
103
+ ex_msg: "error in #{hash}: count should be a positive Integer",
104
+ comply: false
105
+ }
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "constants"
4
+
5
+ #
6
+ # Encode data with RLE.
7
+ #
8
+ module Encoder
9
+ include Constants
10
+
11
+ #
12
+ # Check and then pass data to the actual encoder.
13
+ #
14
+ # @param [Array, String, Enumerator] data
15
+ # Data to encode.
16
+ #
17
+ # @param [String, Regexp] separator ("")
18
+ # Separator for the string arguments.
19
+ #
20
+ # @return [Array<Hash{ Symbol => Object }>]
21
+ # Encoded data. Each element is a Hash with the following key-value pairs:
22
+ # [Constants::CHUNK_KEY => Object]
23
+ # A repeated object.
24
+ #
25
+ # [Constants::COUNT_KEY => Integer]
26
+ # How many times the object is repeated.
27
+ #
28
+ # @raise [ArgumentError, TypeError]
29
+ # Raises if data isn't an Array/String/Enumerator [TypeError] or an empty Array [ArgumentError].
30
+ #
31
+ def encode(data, separator = "")
32
+ valid_data, ex_details = _check_enc_data(data, separator)
33
+
34
+ raise(ex_details[:ex_type], ex_details[:ex_msg]) if ex_details
35
+
36
+ _encode(valid_data)
37
+ end
38
+
39
+ private
40
+
41
+ #
42
+ # Check if data is an array, convert to an array if possible.
43
+ #
44
+ # @return [Array] data
45
+ # Ready-to-be-encoded data.
46
+ #
47
+ # @return [Hash{ Symbol => Object }] ex_details
48
+ # Exception type and error if data can't be encoded.
49
+ #
50
+ def _check_enc_data(data, separator)
51
+ ex_details = nil
52
+
53
+ case data
54
+ when Array
55
+ array = data
56
+ when String
57
+ array = data.split(separator)
58
+ when Enumerator
59
+ array = data.to_a
60
+ else
61
+ ex_details = {
62
+ ex_type: TypeError,
63
+ ex_msg: "wrong argument type #{data.class} (expected Array, String or Enumerator)"
64
+ }
65
+ end
66
+
67
+ if array.to_a.empty?
68
+ ex_details = {
69
+ ex_type: ArgumentError,
70
+ ex_msg: "the given data is empty (no data to encode)"
71
+ }
72
+ end
73
+
74
+ return array, ex_details
75
+ end
76
+
77
+ #
78
+ # Encode array using run-length encoding.
79
+ #
80
+ # @param [Array] data
81
+ # Data to encode.
82
+ #
83
+ # @return [Array<Hash{ Symbol => Object }>]
84
+ # Encoded data. Each element is a Hash with the following key-value pairs:
85
+ # [Constants::CHUNK_KEY => Object]
86
+ # A repeated object.
87
+ #
88
+ # [Constants::COUNT_KEY => Integer]
89
+ # How many times the object is repeated.
90
+ #
91
+ def _encode(data)
92
+ result = []
93
+
94
+ data.each.inject([]) do |memo, element|
95
+ if memo.last && element == memo.last.last
96
+ memo.last[0] += 1
97
+ else
98
+ memo << [1, element]
99
+ end
100
+ result = memo
101
+ end
102
+ result.map { |count, chunk| { CHUNK_KEY => chunk, COUNT_KEY => count } }
103
+ end
104
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RunLengthEncoding
4
+ VERSION = "0.2.1"
5
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "run_length_encoding/version"
4
+ require_relative "run_length_encoding/decoder"
5
+ require_relative "run_length_encoding/encoder"
6
+
7
+ #
8
+ # Provides methods to encode and decode data using RLE.
9
+ #
10
+ class RunLengthEncoding
11
+ include Encoder
12
+ include Decoder
13
+
14
+ def initialize(*); end
15
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/run_length_encoding/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "run_length_encoding_rb"
7
+ spec.version = RunLengthEncoding::VERSION
8
+ spec.authors = ["8bit-mate"]
9
+
10
+ spec.summary = "Run-length encoding/decoding."
11
+ spec.homepage = "https://github.com/8bit-mate/run_length_encoding.rb"
12
+ spec.license = "MIT"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
+
15
+ spec.metadata["allowed_push_host"] = "https://rubygems.org/"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/8bit-mate/run_length_encoding.rb"
19
+ spec.metadata["changelog_uri"] = "https://github.com/8bit-mate/run_length_encoding.rb/blob/main/CHANGELOG.md"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ # Uncomment to register a new dependency of your gem
31
+ # spec.add_dependency "example-gem", "~> 1.0"
32
+
33
+ # For more information and examples about making a new gem, checkout our
34
+ # guide at: https://bundler.io/guides/creating_gem.html
35
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: run_length_encoding_rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - 8bit-mate
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-01-24 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - ".gitignore"
20
+ - ".rubocop.yml"
21
+ - CHANGELOG.md
22
+ - Gemfile
23
+ - Gemfile.lock
24
+ - LICENSE.txt
25
+ - README.md
26
+ - Rakefile
27
+ - bin/console
28
+ - bin/setup
29
+ - lib/run_length_encoding.rb
30
+ - lib/run_length_encoding/constants.rb
31
+ - lib/run_length_encoding/decoder.rb
32
+ - lib/run_length_encoding/decoding_element_check.rb
33
+ - lib/run_length_encoding/encoder.rb
34
+ - lib/run_length_encoding/version.rb
35
+ - run_length_encoding.gemspec
36
+ homepage: https://github.com/8bit-mate/run_length_encoding.rb
37
+ licenses:
38
+ - MIT
39
+ metadata:
40
+ allowed_push_host: https://rubygems.org/
41
+ homepage_uri: https://github.com/8bit-mate/run_length_encoding.rb
42
+ source_code_uri: https://github.com/8bit-mate/run_length_encoding.rb
43
+ changelog_uri: https://github.com/8bit-mate/run_length_encoding.rb/blob/main/CHANGELOG.md
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 2.3.0
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.2.3
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Run-length encoding/decoding.
63
+ test_files: []