denormalizer 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6 -0
- data/README.rdoc +7 -5
- data/VERSION +1 -1
- data/app/models/denormalizer/method_output.rb +9 -0
- data/denormalizer.gemspec +128 -0
- data/lib/denormalizer/denormalize.rb +19 -9
- data/spec/association_denormalization_spec.rb +39 -0
- data/spec/denormalize_all_spec.rb +21 -0
- data/spec/method_denormalization_spec.rb +87 -0
- metadata +7 -3
data/CHANGELOG
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
== unreleased changes
|
2
2
|
|
3
|
+
== 0.0.2
|
4
|
+
|
5
|
+
* Added basic testing for the mixins
|
6
|
+
* Changed the scope names to plurals
|
7
|
+
* Added instance methods to check for individual denormalized method outputs
|
8
|
+
|
3
9
|
== 0.0.1
|
4
10
|
|
5
11
|
* Added mixin with denormalize_all, denormalize, and also_denormalize methods
|
data/README.rdoc
CHANGED
@@ -31,10 +31,10 @@ Denormalize associations. This will run the denormalization method on each of t
|
|
31
31
|
|
32
32
|
Use the denormalized data
|
33
33
|
|
34
|
-
Book.
|
35
|
-
Book.
|
34
|
+
Book.denormalized_actives
|
35
|
+
Book.denormalized_not_actives
|
36
36
|
|
37
|
-
Book.first.denormalized_active?
|
37
|
+
Book.first.denormalized_active?
|
38
38
|
|
39
39
|
== Thought Process
|
40
40
|
|
@@ -56,8 +56,10 @@ The first minimizes code duplication but is not chainable and often slower than
|
|
56
56
|
|
57
57
|
== Todo
|
58
58
|
|
59
|
-
*
|
60
|
-
*
|
59
|
+
* Add code to make sure association denormalization does loop infinitely
|
60
|
+
* Improve testing on the Denormalizer::MethodOutput model
|
61
|
+
* Refactor dome of the denormalize mixin code to the MethodOutput model
|
62
|
+
* Figure out how to replace mysql with a different database/memory store system
|
61
63
|
|
62
64
|
== Contributing to denormalizer
|
63
65
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
@@ -6,4 +6,13 @@ class Denormalizer::MethodOutput < ActiveRecord::Base
|
|
6
6
|
|
7
7
|
FalseOutput = 0
|
8
8
|
TrueOutput = 1
|
9
|
+
|
10
|
+
def self.by_object_and_method_name(obj, method_name)
|
11
|
+
attributes = {
|
12
|
+
:denormalized_object_type => obj.class.name,
|
13
|
+
:denormalized_object_id => obj.id,
|
14
|
+
:denormalized_object_method => method_name
|
15
|
+
}
|
16
|
+
where(attributes).limit(1)
|
17
|
+
end
|
9
18
|
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "denormalizer"
|
8
|
+
s.version = "0.0.2"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jeremiah Hemphill"]
|
12
|
+
s.date = "2012-07-13"
|
13
|
+
s.description = "Cache method outputs and automatically create chainable scopes based on their outputs"
|
14
|
+
s.email = "jeremiah@cloudspace.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
"CHANGELOG",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"app/models/denormalizer/method_output.rb",
|
30
|
+
"denormalizer.gemspec",
|
31
|
+
"lib/denormalizer.rb",
|
32
|
+
"lib/denormalizer/config.rb",
|
33
|
+
"lib/denormalizer/denormalize.rb",
|
34
|
+
"lib/denormalizer/engine.rb",
|
35
|
+
"lib/denormalizer/railtie.rb",
|
36
|
+
"lib/generators/denormalizer/install_generator.rb",
|
37
|
+
"lib/generators/denormalizer/templates/config.rb",
|
38
|
+
"lib/generators/denormalizer/templates/migrations/install_migration.rb.erb",
|
39
|
+
"spec/association_denormalization_spec.rb",
|
40
|
+
"spec/denormalize_all_spec.rb",
|
41
|
+
"spec/denormalizer_spec.rb",
|
42
|
+
"spec/dummy/Rakefile",
|
43
|
+
"spec/dummy/app/controllers/application_controller.rb",
|
44
|
+
"spec/dummy/app/helpers/application_helper.rb",
|
45
|
+
"spec/dummy/app/models/book.rb",
|
46
|
+
"spec/dummy/app/models/printing.rb",
|
47
|
+
"spec/dummy/app/views/layouts/application.html.erb",
|
48
|
+
"spec/dummy/config.ru",
|
49
|
+
"spec/dummy/config/application.rb",
|
50
|
+
"spec/dummy/config/boot.rb",
|
51
|
+
"spec/dummy/config/database.yml",
|
52
|
+
"spec/dummy/config/environment.rb",
|
53
|
+
"spec/dummy/config/environments/development.rb",
|
54
|
+
"spec/dummy/config/environments/production.rb",
|
55
|
+
"spec/dummy/config/environments/test.rb",
|
56
|
+
"spec/dummy/config/initializers/backtrace_silencers.rb",
|
57
|
+
"spec/dummy/config/initializers/denormalizer.rb",
|
58
|
+
"spec/dummy/config/initializers/inflections.rb",
|
59
|
+
"spec/dummy/config/initializers/mime_types.rb",
|
60
|
+
"spec/dummy/config/initializers/secret_token.rb",
|
61
|
+
"spec/dummy/config/initializers/session_store.rb",
|
62
|
+
"spec/dummy/config/locales/en.yml",
|
63
|
+
"spec/dummy/config/routes.rb",
|
64
|
+
"spec/dummy/db/migrate/20120706021202_book.rb",
|
65
|
+
"spec/dummy/db/migrate/20120706125004_create_denormalizer_tables.rb",
|
66
|
+
"spec/dummy/db/schema.rb",
|
67
|
+
"spec/dummy/public/404.html",
|
68
|
+
"spec/dummy/public/422.html",
|
69
|
+
"spec/dummy/public/500.html",
|
70
|
+
"spec/dummy/public/favicon.ico",
|
71
|
+
"spec/dummy/public/javascripts/application.js",
|
72
|
+
"spec/dummy/public/javascripts/controls.js",
|
73
|
+
"spec/dummy/public/javascripts/dragdrop.js",
|
74
|
+
"spec/dummy/public/javascripts/effects.js",
|
75
|
+
"spec/dummy/public/javascripts/prototype.js",
|
76
|
+
"spec/dummy/public/javascripts/rails.js",
|
77
|
+
"spec/dummy/public/stylesheets/.gitkeep",
|
78
|
+
"spec/dummy/script/rails",
|
79
|
+
"spec/integration/navigation_spec.rb",
|
80
|
+
"spec/method_denormalization_spec.rb",
|
81
|
+
"spec/spec_helper.rb"
|
82
|
+
]
|
83
|
+
s.homepage = "http://github.com/jeremiahishere/denormalizer"
|
84
|
+
s.licenses = ["MIT"]
|
85
|
+
s.require_paths = ["lib"]
|
86
|
+
s.rubygems_version = "1.8.15"
|
87
|
+
s.summary = "Cache method outputs"
|
88
|
+
|
89
|
+
if s.respond_to? :specification_version then
|
90
|
+
s.specification_version = 3
|
91
|
+
|
92
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
93
|
+
s.add_runtime_dependency(%q<rails>, [">= 3.0.0"])
|
94
|
+
s.add_development_dependency(%q<capybara>, [">= 0.4.0"])
|
95
|
+
s.add_development_dependency(%q<sqlite3>, [">= 0"])
|
96
|
+
s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
|
97
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.6.0"])
|
98
|
+
s.add_development_dependency(%q<rspec-rails>, ["~> 2.6.1"])
|
99
|
+
s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
|
100
|
+
s.add_development_dependency(%q<database_cleaner>, [">= 0"])
|
101
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.3"])
|
102
|
+
s.add_development_dependency(%q<ci_reporter>, [">= 0"])
|
103
|
+
else
|
104
|
+
s.add_dependency(%q<rails>, [">= 3.0.0"])
|
105
|
+
s.add_dependency(%q<capybara>, [">= 0.4.0"])
|
106
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
107
|
+
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
108
|
+
s.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
109
|
+
s.add_dependency(%q<rspec-rails>, ["~> 2.6.1"])
|
110
|
+
s.add_dependency(%q<yard>, ["~> 0.6.0"])
|
111
|
+
s.add_dependency(%q<database_cleaner>, [">= 0"])
|
112
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.3"])
|
113
|
+
s.add_dependency(%q<ci_reporter>, [">= 0"])
|
114
|
+
end
|
115
|
+
else
|
116
|
+
s.add_dependency(%q<rails>, [">= 3.0.0"])
|
117
|
+
s.add_dependency(%q<capybara>, [">= 0.4.0"])
|
118
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
119
|
+
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
120
|
+
s.add_dependency(%q<rspec>, ["~> 2.6.0"])
|
121
|
+
s.add_dependency(%q<rspec-rails>, ["~> 2.6.1"])
|
122
|
+
s.add_dependency(%q<yard>, ["~> 0.6.0"])
|
123
|
+
s.add_dependency(%q<database_cleaner>, [">= 0"])
|
124
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.3"])
|
125
|
+
s.add_dependency(%q<ci_reporter>, [">= 0"])
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
@@ -35,7 +35,7 @@ module Denormalizer
|
|
35
35
|
"denormalizer_method_outputs.denormalized_object_method" => method_name.to_s,
|
36
36
|
"denormalizer_method_outputs.method_output" => Denormalizer::MethodOutput::TrueOutput
|
37
37
|
}
|
38
|
-
true_scope_name = "denormalized_#{method_name.to_s.gsub('?', '')}".to_sym
|
38
|
+
true_scope_name = "denormalized_#{method_name.to_s.gsub('?', '')}".pluralize.to_sym
|
39
39
|
scope true_scope_name, lambda { joins(:denormalized_method_outputs).where(true_attributes)}
|
40
40
|
|
41
41
|
# setup false scope
|
@@ -43,8 +43,14 @@ module Denormalizer
|
|
43
43
|
"denormalizer_method_outputs.denormalized_object_method" => method_name.to_s,
|
44
44
|
"denormalizer_method_outputs.method_output" => Denormalizer::MethodOutput::FalseOutput
|
45
45
|
}
|
46
|
-
false_scope_name = "denormalized_not_#{method_name.to_s.gsub('?', '')}".to_sym
|
46
|
+
false_scope_name = "denormalized_not_#{method_name.to_s.gsub('?', '')}".pluralize.to_sym
|
47
47
|
scope false_scope_name, lambda { joins(:denormalized_method_outputs).where(false_attributes)}
|
48
|
+
|
49
|
+
instance_method_name = "denormalized_#{method_name.to_s}"
|
50
|
+
define_method instance_method_name do
|
51
|
+
saved_output = Denormalizer::MethodOutput.by_object_and_method_name(self, method_name).first
|
52
|
+
return saved_output.method_output == Denormalizer::MethodOutput::TrueOutput
|
53
|
+
end
|
48
54
|
end
|
49
55
|
|
50
56
|
after_save :method_denormalization
|
@@ -76,14 +82,16 @@ module Denormalizer
|
|
76
82
|
method_output = self.send(method_name) ? Denormalizer::MethodOutput::TrueOutput : Denormalizer::MethodOutput::FalseOutput
|
77
83
|
|
78
84
|
# find a match then create or update based on success
|
79
|
-
|
80
|
-
|
81
|
-
:denormalized_object_id => self.id,
|
82
|
-
:denormalized_object_method => method_name
|
83
|
-
}
|
84
|
-
saved_output = Denormalizer::MethodOutput.where(attributes).limit(1).first
|
85
|
+
# TODO: refactor this entire section to metho on Denormalizer::MethodOutput (JH 7-13-2012)
|
86
|
+
saved_output = Denormalizer::MethodOutput.by_object_and_method_name(self, method_name).first
|
85
87
|
if saved_output.nil?
|
86
|
-
|
88
|
+
attributes = {
|
89
|
+
:denormalized_object_type => self.class.name,
|
90
|
+
:denormalized_object_id => self.id,
|
91
|
+
:denormalized_object_method => method_name,
|
92
|
+
:method_output => method_output
|
93
|
+
}
|
94
|
+
Denormalizer::MethodOutput.create(attributes)
|
87
95
|
else
|
88
96
|
saved_output.method_output = method_output
|
89
97
|
saved_output.save
|
@@ -93,6 +101,8 @@ module Denormalizer
|
|
93
101
|
end
|
94
102
|
|
95
103
|
def association_denormalization
|
104
|
+
# TODO: make sure this doesn't loop infinitely (JH 7-13-2012)
|
105
|
+
# if two models have a circular association or a model has a self association, this will not work
|
96
106
|
self.denormalized_associations.each do |assoc_method|
|
97
107
|
assoc = self.send(assoc_method)
|
98
108
|
if assoc.is_a?(Array)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "association denormalization" do
|
4
|
+
before(:each) { @printing = Printing.new }
|
5
|
+
subject { @printing }
|
6
|
+
|
7
|
+
describe "class methods" do
|
8
|
+
describe "also_denormalize" do
|
9
|
+
it "should add to the denormalized_associations array" do
|
10
|
+
@printing.denormalized_associations.should include :book
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should add association_denormalization to the after_save" do
|
14
|
+
@printing.should_receive(:association_denormalization)
|
15
|
+
@printing.save(:validate => false)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "instance methods" do
|
21
|
+
describe "association_denormalization" do
|
22
|
+
before(:each) do
|
23
|
+
@book = Book.new
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should call method_denormalization for the association" do
|
27
|
+
@printing.book = @book
|
28
|
+
@book.should_receive(:method_denormalization)
|
29
|
+
@printing.association_denormalization
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should call method_denormalization for each member of the association if it is an array" do
|
33
|
+
@printing.stub(:book).and_return([@book])
|
34
|
+
@book.should_receive(:method_denormalization)
|
35
|
+
@printing.association_denormalization
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "denormalize_all" do
|
4
|
+
describe "class methods" do
|
5
|
+
describe "denormalize_all" do
|
6
|
+
it "should call method_denormalization on all instances of the object" do
|
7
|
+
@book = Book.new
|
8
|
+
Book.stub(:all).and_return([@book])
|
9
|
+
@book.should_receive(:method_denormalization)
|
10
|
+
Book.denormalize_all
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should call association_denormalization on all instances of the object" do
|
14
|
+
@printing = Printing.new
|
15
|
+
Printing.stub(:all).and_return([@printing])
|
16
|
+
@printing.should_receive(:association_denormalization)
|
17
|
+
Printing.denormalize_all
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ruby-debug'
|
3
|
+
|
4
|
+
describe "method denormalization" do
|
5
|
+
before(:each) { @book = Book.new }
|
6
|
+
subject { @book }
|
7
|
+
|
8
|
+
describe "class methods" do
|
9
|
+
describe "denormalize" do
|
10
|
+
it "should add to the denormalized_method_outputs array" do
|
11
|
+
@book.denormalized_methods.should include :short_name?
|
12
|
+
@book.denormalized_methods.should include :printed?
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should create a scope called denormalized_method_names for the method method_name?" do
|
16
|
+
Book.should respond_to :denormalized_short_names
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should create a scope called denormalized_not_method_names for the method method_name?" do
|
20
|
+
Book.should respond_to :denormalized_not_short_names
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should add method_denormalization to the after_save" do
|
24
|
+
@book.should_receive(:method_denormalization)
|
25
|
+
@book.save(:validate => false)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# these tests are dependent on the Book model denormalizing the short_name? and printed?
|
31
|
+
describe "scopes" do
|
32
|
+
describe "denormalized_short_names" do
|
33
|
+
it "should match this sql" do
|
34
|
+
sql = Book.denormalized_short_names.to_sql
|
35
|
+
sql.should match "INNER JOIN \"denormalizer_method_outputs\" ON \"denormalizer_method_outputs\".\"denormalized_object_id\" = \"books\".\"id\" AND \"denormalizer_method_outputs\".\"denormalized_object_type\" = 'Book'"
|
36
|
+
sql.should match "WHERE \"denormalizer_method_outputs\".\"denormalized_object_method\" = 'short_name.' AND \"denormalizer_method_outputs\".\"method_output\" = 1"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "denormalized_not_short_names" do
|
41
|
+
it "should match this sql" do
|
42
|
+
sql = Book.denormalized_not_short_names.to_sql
|
43
|
+
sql.should match "INNER JOIN \"denormalizer_method_outputs\" ON \"denormalizer_method_outputs\".\"denormalized_object_id\" = \"books\".\"id\" AND \"denormalizer_method_outputs\".\"denormalized_object_type\" = 'Book'"
|
44
|
+
sql.should match "WHERE \"denormalizer_method_outputs\".\"denormalized_object_method\" = 'short_name.' AND \"denormalizer_method_outputs\".\"method_output\" = 0"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "methods" do
|
50
|
+
describe "denormalized_short_name?" do
|
51
|
+
it "should include the denormalized method" do
|
52
|
+
@book.should respond_to :denormalized_short_name?
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should match the actual output if synced" do
|
56
|
+
@book.name = "abc"
|
57
|
+
@book.save
|
58
|
+
@book.short_name?.should equal @book.denormalized_short_name?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "method_denormalization" do
|
63
|
+
before(:each) do
|
64
|
+
@book.stub(:new_record?).and_return(false)
|
65
|
+
@book.stub(:id).and_return(1000)
|
66
|
+
@book.name = "The Tale of Two Cities"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should do nothing for new records" do
|
70
|
+
@book.stub(:new_record?).and_return(true)
|
71
|
+
@book.should_not_receive(:denormalized_methods)
|
72
|
+
@book.method_denormalization
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should call each denormalized method" do
|
76
|
+
@book.should_receive(:short_name?)
|
77
|
+
@book.should_receive(:printed?)
|
78
|
+
@book.method_denormalization
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should save the output of each denormalized method to the database" do
|
82
|
+
@book.method_denormalization
|
83
|
+
Denormalizer::MethodOutput.where(:denormalized_object_type => "Book", :denormalized_object_id => 1000, :denormalized_object_method => "short_name?").should_not be_empty
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: denormalizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Jeremiah Hemphill
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-07-
|
13
|
+
date: 2012-07-13 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
@@ -142,6 +142,7 @@ files:
|
|
142
142
|
- Rakefile
|
143
143
|
- VERSION
|
144
144
|
- app/models/denormalizer/method_output.rb
|
145
|
+
- denormalizer.gemspec
|
145
146
|
- lib/denormalizer.rb
|
146
147
|
- lib/denormalizer/config.rb
|
147
148
|
- lib/denormalizer/denormalize.rb
|
@@ -150,6 +151,8 @@ files:
|
|
150
151
|
- lib/generators/denormalizer/install_generator.rb
|
151
152
|
- lib/generators/denormalizer/templates/config.rb
|
152
153
|
- lib/generators/denormalizer/templates/migrations/install_migration.rb.erb
|
154
|
+
- spec/association_denormalization_spec.rb
|
155
|
+
- spec/denormalize_all_spec.rb
|
153
156
|
- spec/denormalizer_spec.rb
|
154
157
|
- spec/dummy/Rakefile
|
155
158
|
- spec/dummy/app/controllers/application_controller.rb
|
@@ -189,6 +192,7 @@ files:
|
|
189
192
|
- spec/dummy/public/stylesheets/.gitkeep
|
190
193
|
- spec/dummy/script/rails
|
191
194
|
- spec/integration/navigation_spec.rb
|
195
|
+
- spec/method_denormalization_spec.rb
|
192
196
|
- spec/spec_helper.rb
|
193
197
|
homepage: http://github.com/jeremiahishere/denormalizer
|
194
198
|
licenses:
|
@@ -203,7 +207,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
203
207
|
requirements:
|
204
208
|
- - ">="
|
205
209
|
- !ruby/object:Gem::Version
|
206
|
-
hash:
|
210
|
+
hash: 3695816084296706715
|
207
211
|
segments:
|
208
212
|
- 0
|
209
213
|
version: "0"
|