tangram 0.1.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +23 -19
- data/docs/Tangram.html +127 -0
- data/docs/Tangram/BagOfWordsFeatureContribution.html +507 -0
- data/docs/Tangram/Bigram.html +363 -0
- data/docs/Tangram/BinaryClassificationPredictOutput.html +493 -0
- data/docs/Tangram/FeatureContributions.html +435 -0
- data/docs/Tangram/IdentityFeatureContribution.html +435 -0
- data/docs/Tangram/LibTangram.html +160 -0
- data/docs/Tangram/LibTangram/TangramStringView.html +193 -0
- data/docs/Tangram/LoadModelOptions.html +291 -0
- data/docs/Tangram/Model.html +1250 -0
- data/docs/Tangram/MulticlassClassificationPredictOutput.html +565 -0
- data/docs/Tangram/NormalizedFeatureContribution.html +435 -0
- data/docs/Tangram/OneHotEncodedFeatureContribution.html +507 -0
- data/docs/Tangram/PredictOptions.html +421 -0
- data/docs/Tangram/RegressionPredictOutput.html +421 -0
- data/docs/Tangram/Unigram.html +291 -0
- data/docs/Tangram/WordEmbeddingFeatureContribution.html +435 -0
- data/docs/_index.html +310 -0
- data/docs/class_list.html +51 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +58 -0
- data/docs/css/style.css +497 -0
- data/docs/file.README.html +128 -0
- data/docs/file_list.html +56 -0
- data/docs/frames.html +17 -0
- data/docs/index.html +128 -0
- data/docs/js/app.js +314 -0
- data/docs/js/full_list.js +216 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +555 -0
- data/docs/top-level-namespace.html +110 -0
- data/examples/advanced.rb +49 -0
- data/examples/basic.rb +29 -0
- data/examples/heart_disease.tangram +0 -0
- data/lib/tangram.rb +1 -1
- data/lib/tangram/libtangram/aarch64-apple-darwin/libtangram.dylib +0 -0
- data/lib/tangram/libtangram/x86_64-apple-darwin/libtangram.dylib +0 -0
- data/lib/tangram/libtangram/x86_64-pc-windows-msvc/tangram.dll +0 -0
- data/lib/tangram/libtangram/x86_64-unknown-linux-gnu/libtangram.so +0 -0
- data/lib/tangram/libtangram/x86_64-unknown-linux-musl/libtangram.so +0 -0
- data/lib/tangram/tangram.rb +841 -0
- data/scripts/build +2 -4
- data/scripts/dev +4 -0
- data/scripts/docs +1 -0
- data/scripts/fmt +0 -0
- data/scripts/release +1 -0
- data/tangram.gemspec +10 -10
- metadata +52 -17
- data/examples/monitor/heart-disease.tangram +0 -0
- data/examples/monitor/main.rb +0 -52
- data/examples/predict/heart-disease.tangram +0 -0
- data/examples/predict/main.rb +0 -30
- data/lib/tangram/libtangram-0.1.3-linux-x86_64.so +0 -0
- data/lib/tangram/libtangram-0.1.3-macos-x86_64.dylib +0 -0
- data/lib/tangram/libtangram.rb +0 -24
- data/lib/tangram/model.rb +0 -133
- data/lib/tangram/tangram-0.1.3-windows-x86_64.dll +0 -0
data/scripts/build
CHANGED
data/scripts/dev
ADDED
data/scripts/docs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
yard -m markdown -o docs
|
data/scripts/fmt
ADDED
|
File without changes
|
data/scripts/release
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
gem publish dist/*
|
data/tangram.gemspec
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Gem::Specification.new do |s|
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
s.name = "tangram"
|
|
3
|
+
s.version = "0.3.0"
|
|
4
|
+
s.summary = "Tangram for Ruby"
|
|
5
|
+
s.description = "Make predictions with a Tangram model from your Ruby app. Learn more at https://www.tangram.xyz/."
|
|
6
|
+
s.authors = ["Tangram"]
|
|
7
|
+
s.email = "help@tangram.xyz"
|
|
8
|
+
s.files = Dir["**/**"].grep_v(/.gem$/)
|
|
9
|
+
s.homepage = "http://rubygems.org/gems/tangram"
|
|
10
|
+
s.license = "MIT"
|
|
11
|
+
s.add_dependency "ffi", "~> 1"
|
|
12
12
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tangram
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tangram
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-04-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ffi
|
|
@@ -25,31 +25,66 @@ dependencies:
|
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '1'
|
|
27
27
|
description: Make predictions with a Tangram model from your Ruby app. Learn more
|
|
28
|
-
at https://www.
|
|
29
|
-
email: help@
|
|
28
|
+
at https://www.tangram.xyz/.
|
|
29
|
+
email: help@tangram.xyz
|
|
30
30
|
executables: []
|
|
31
31
|
extensions: []
|
|
32
32
|
extra_rdoc_files: []
|
|
33
33
|
files:
|
|
34
34
|
- LICENSE
|
|
35
35
|
- README.md
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
36
|
+
- docs/Tangram.html
|
|
37
|
+
- docs/Tangram/BagOfWordsFeatureContribution.html
|
|
38
|
+
- docs/Tangram/Bigram.html
|
|
39
|
+
- docs/Tangram/BinaryClassificationPredictOutput.html
|
|
40
|
+
- docs/Tangram/FeatureContributions.html
|
|
41
|
+
- docs/Tangram/IdentityFeatureContribution.html
|
|
42
|
+
- docs/Tangram/LibTangram.html
|
|
43
|
+
- docs/Tangram/LibTangram/TangramStringView.html
|
|
44
|
+
- docs/Tangram/LoadModelOptions.html
|
|
45
|
+
- docs/Tangram/Model.html
|
|
46
|
+
- docs/Tangram/MulticlassClassificationPredictOutput.html
|
|
47
|
+
- docs/Tangram/NormalizedFeatureContribution.html
|
|
48
|
+
- docs/Tangram/OneHotEncodedFeatureContribution.html
|
|
49
|
+
- docs/Tangram/PredictOptions.html
|
|
50
|
+
- docs/Tangram/RegressionPredictOutput.html
|
|
51
|
+
- docs/Tangram/Unigram.html
|
|
52
|
+
- docs/Tangram/WordEmbeddingFeatureContribution.html
|
|
53
|
+
- docs/_index.html
|
|
54
|
+
- docs/class_list.html
|
|
55
|
+
- docs/css/common.css
|
|
56
|
+
- docs/css/full_list.css
|
|
57
|
+
- docs/css/style.css
|
|
58
|
+
- docs/file.README.html
|
|
59
|
+
- docs/file_list.html
|
|
60
|
+
- docs/frames.html
|
|
61
|
+
- docs/index.html
|
|
62
|
+
- docs/js/app.js
|
|
63
|
+
- docs/js/full_list.js
|
|
64
|
+
- docs/js/jquery.js
|
|
65
|
+
- docs/method_list.html
|
|
66
|
+
- docs/top-level-namespace.html
|
|
67
|
+
- examples/advanced.rb
|
|
68
|
+
- examples/basic.rb
|
|
69
|
+
- examples/heart_disease.tangram
|
|
40
70
|
- lib/tangram.rb
|
|
41
|
-
- lib/tangram/libtangram-
|
|
42
|
-
- lib/tangram/libtangram-
|
|
43
|
-
- lib/tangram/libtangram.
|
|
44
|
-
- lib/tangram/
|
|
45
|
-
- lib/tangram/
|
|
71
|
+
- lib/tangram/libtangram/aarch64-apple-darwin/libtangram.dylib
|
|
72
|
+
- lib/tangram/libtangram/x86_64-apple-darwin/libtangram.dylib
|
|
73
|
+
- lib/tangram/libtangram/x86_64-pc-windows-msvc/tangram.dll
|
|
74
|
+
- lib/tangram/libtangram/x86_64-unknown-linux-gnu/libtangram.so
|
|
75
|
+
- lib/tangram/libtangram/x86_64-unknown-linux-musl/libtangram.so
|
|
76
|
+
- lib/tangram/tangram.rb
|
|
46
77
|
- scripts/build
|
|
78
|
+
- scripts/dev
|
|
79
|
+
- scripts/docs
|
|
80
|
+
- scripts/fmt
|
|
81
|
+
- scripts/release
|
|
47
82
|
- tangram.gemspec
|
|
48
83
|
homepage: http://rubygems.org/gems/tangram
|
|
49
84
|
licenses:
|
|
50
85
|
- MIT
|
|
51
86
|
metadata: {}
|
|
52
|
-
post_install_message:
|
|
87
|
+
post_install_message:
|
|
53
88
|
rdoc_options: []
|
|
54
89
|
require_paths:
|
|
55
90
|
- lib
|
|
@@ -64,8 +99,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
64
99
|
- !ruby/object:Gem::Version
|
|
65
100
|
version: '0'
|
|
66
101
|
requirements: []
|
|
67
|
-
rubygems_version: 3.
|
|
68
|
-
signing_key:
|
|
102
|
+
rubygems_version: 3.2.15
|
|
103
|
+
signing_key:
|
|
69
104
|
specification_version: 4
|
|
70
105
|
summary: Tangram for Ruby
|
|
71
106
|
test_files: []
|
|
Binary file
|
data/examples/monitor/main.rb
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
require 'tangram'
|
|
2
|
-
|
|
3
|
-
# Go to https://app.tangramhq.com or your private instance, upload the `heart-disease.tangram` file adjacent to this file, generate a token, and pass it as an environment variable to this script.
|
|
4
|
-
token = ENV['TANGRAM_TOKEN']
|
|
5
|
-
if token.nil?
|
|
6
|
-
raise 'TANGRAM_TOKEN environment variable not set'
|
|
7
|
-
end
|
|
8
|
-
base_url = ENV['TANGRAM_BASE_URL'] || 'https://app.tangramhq.com'
|
|
9
|
-
|
|
10
|
-
# Get the path to the `.tangram` file.
|
|
11
|
-
model_path = File.join(File.dirname(__FILE__), 'heart-disease.tangram')
|
|
12
|
-
# Load the model from the file and set the Tangram API token and base url.
|
|
13
|
-
model = Tangram::Model.from_file(model_path, token: token, base_url: base_url)
|
|
14
|
-
|
|
15
|
-
# Create an example input matching the schema of the CSV file the model was trained on. Here the data is just hard-coded, but in your application you will probably get this from a database or user input.
|
|
16
|
-
input = {
|
|
17
|
-
age: 63,
|
|
18
|
-
gender: 'male',
|
|
19
|
-
chest_pain: 'typical angina',
|
|
20
|
-
resting_blood_pressure: 145,
|
|
21
|
-
cholesterol: 233,
|
|
22
|
-
fasting_blood_sugar_greater_than_120: 'true',
|
|
23
|
-
resting_ecg_result: 'probable or definite left ventricular hypertrophy',
|
|
24
|
-
exercise_max_heart_rate: 150,
|
|
25
|
-
exercise_induced_angina: 'no',
|
|
26
|
-
exercise_st_depression: 2.3,
|
|
27
|
-
exercise_st_slope: 'downsloping',
|
|
28
|
-
fluoroscopy_vessels_colored: 0,
|
|
29
|
-
thallium_stress_test: 'fixed defect',
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
# Make the prediction using a custom threshold chosen on the "Tuning" page of the Tangram reporting and monitoring app.
|
|
33
|
-
options = { threshold: 0.25 }
|
|
34
|
-
output = model.predict(input, options: options)
|
|
35
|
-
|
|
36
|
-
# Make the prediction using a custom threshold chosen on the "Tuning" page of the Tangram reporting and monitoring app.
|
|
37
|
-
puts('Input:', input)
|
|
38
|
-
puts('Output:', output)
|
|
39
|
-
|
|
40
|
-
# Log the prediction. This will allow us to view production stats in the Tangram reporting and monitoring app.
|
|
41
|
-
model.log_prediction(
|
|
42
|
-
identifier: 'John Doe',
|
|
43
|
-
options: options,
|
|
44
|
-
input: input,
|
|
45
|
-
output: output,
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
# Later on, if we get an official diagnosis for the patient, we can log the true value for the prior prediction. Make sure to match the `identifier` from the former prediction.
|
|
49
|
-
model.log_true_value(
|
|
50
|
-
identifier: 'John Doe',
|
|
51
|
-
true_value: 'Positive',
|
|
52
|
-
)
|
|
Binary file
|
data/examples/predict/main.rb
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
require 'tangram'
|
|
2
|
-
|
|
3
|
-
# Get the path to the .tangram file.
|
|
4
|
-
model_path = File.join(File.dirname(__FILE__), 'heart-disease.tangram')
|
|
5
|
-
# Load the model from the file.
|
|
6
|
-
model = Tangram::Model.from_file(model_path)
|
|
7
|
-
|
|
8
|
-
# Create an example input matching the schema of the CSV file the model was trained on. Here the data is just hard-coded, but in your application you will probably get this from a database or user input.
|
|
9
|
-
input = {
|
|
10
|
-
age: 63,
|
|
11
|
-
gender: 'male',
|
|
12
|
-
chest_pain: 'typical angina',
|
|
13
|
-
resting_blood_pressure: 145,
|
|
14
|
-
cholesterol: 233,
|
|
15
|
-
fasting_blood_sugar_greater_than_120: 'true',
|
|
16
|
-
resting_ecg_result: 'probable or definite left ventricular hypertrophy',
|
|
17
|
-
exercise_max_heart_rate: 150,
|
|
18
|
-
exercise_induced_angina: 'no',
|
|
19
|
-
exercise_st_depression: 2.3,
|
|
20
|
-
exercise_st_slope: 'downsloping',
|
|
21
|
-
fluoroscopy_vessels_colored: 0,
|
|
22
|
-
thallium_stress_test: 'fixed defect',
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
# Make the prediction!
|
|
26
|
-
output = model.predict(input)
|
|
27
|
-
|
|
28
|
-
# Print out the input and output.
|
|
29
|
-
puts('Input:', input)
|
|
30
|
-
puts('Output:', output)
|
|
Binary file
|
|
Binary file
|
data/lib/tangram/libtangram.rb
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
require 'ffi'
|
|
2
|
-
require 'rbconfig'
|
|
3
|
-
|
|
4
|
-
module LibTangram
|
|
5
|
-
cpu = RbConfig::CONFIG['host_cpu']
|
|
6
|
-
os = RbConfig::CONFIG['host_os']
|
|
7
|
-
if cpu == 'x86_64' and os =~ /linux/
|
|
8
|
-
library_name = 'libtangram-0.1.3-linux-x86_64.so'
|
|
9
|
-
elsif cpu == 'x86_64' and os =~ /darwin/
|
|
10
|
-
library_name = 'libtangram-0.1.3-macos-x86_64.dylib'
|
|
11
|
-
elsif cpu == 'x86_64' and os =~ /mingw/
|
|
12
|
-
library_name = 'tangram-0.1.3-windows-x86_64.dll'
|
|
13
|
-
else
|
|
14
|
-
raise 'tangram-ruby does not yet support your combination of operating system and CPU architecture. Want support for your platform? Get in touch at help@tangramhq.com.'
|
|
15
|
-
end
|
|
16
|
-
extend FFI::Library
|
|
17
|
-
ffi_lib File.expand_path("#{library_name}", __dir__)
|
|
18
|
-
attach_function :tangram_model_load, [:pointer, :uint, :pointer], :int
|
|
19
|
-
attach_function :tangram_model_id, [:pointer, :pointer], :int
|
|
20
|
-
attach_function :tangram_model_task, [:pointer, :pointer], :int
|
|
21
|
-
attach_function :tangram_model_predict, [:pointer, :pointer, :pointer, :pointer], :int
|
|
22
|
-
attach_function :tangram_string_free, [:pointer], :int
|
|
23
|
-
attach_function :tangram_model_free, [:pointer], :int
|
|
24
|
-
end
|
data/lib/tangram/model.rb
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
require 'json'
|
|
2
|
-
require 'net/http'
|
|
3
|
-
require 'tangram/libtangram'
|
|
4
|
-
|
|
5
|
-
module Tangram
|
|
6
|
-
class Model
|
|
7
|
-
|
|
8
|
-
def self.from_file(model_path, base_url: nil, token: nil)
|
|
9
|
-
model_data = IO.binread(model_path)
|
|
10
|
-
self.from_data(model_data, base_url: base_url, token: token)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def self.from_data(model_data, base_url: nil, token: nil)
|
|
14
|
-
self.new(model_data, base_url: base_url, token: token)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def initialize(model_data, base_url: nil, token: nil)
|
|
18
|
-
@base_url = base_url.nil? ? 'https://app.tangramhq.com' : base_url
|
|
19
|
-
@token = token
|
|
20
|
-
@log_queue = []
|
|
21
|
-
model_ptr = FFI::MemoryPointer.new(:pointer)
|
|
22
|
-
result = LibTangram.tangram_model_load(model_data, model_data.size, model_ptr)
|
|
23
|
-
if result != 0
|
|
24
|
-
raise 'tangram error'
|
|
25
|
-
end
|
|
26
|
-
@model = FFI::AutoPointer.new(model_ptr.read_pointer, LibTangram.method(:tangram_model_free))
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def id()
|
|
30
|
-
id_ptr = FFI::MemoryPointer.new(:pointer)
|
|
31
|
-
result = LibTangram.tangram_model_id(@model, id_ptr)
|
|
32
|
-
if result != 0
|
|
33
|
-
raise 'tangram error'
|
|
34
|
-
end
|
|
35
|
-
id = id_ptr.read_pointer.read_string.force_encoding('utf-8')
|
|
36
|
-
LibTangram.tangram_string_free(id_ptr.read_pointer)
|
|
37
|
-
id
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def task()
|
|
41
|
-
task_ptr = FFI::MemoryPointer.new(:pointer)
|
|
42
|
-
result = LibTangram.tangram_model_task(@model, task_ptr)
|
|
43
|
-
if result != 0
|
|
44
|
-
raise 'tangram error'
|
|
45
|
-
end
|
|
46
|
-
task = task_ptr.read_pointer.read_string.force_encoding('utf-8')
|
|
47
|
-
LibTangram.tangram_string_free(task_ptr.read_pointer)
|
|
48
|
-
task
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def predict(input, options: nil)
|
|
52
|
-
input = JSON.unparse(input)
|
|
53
|
-
unless options.nil?
|
|
54
|
-
options = JSON.unparse(options)
|
|
55
|
-
else
|
|
56
|
-
options = nil
|
|
57
|
-
end
|
|
58
|
-
output_ptr = FFI::MemoryPointer.new(:pointer)
|
|
59
|
-
result = LibTangram.tangram_model_predict(@model, input, options, output_ptr)
|
|
60
|
-
if result != 0
|
|
61
|
-
raise 'tangram error'
|
|
62
|
-
end
|
|
63
|
-
output = output_ptr.read_pointer.read_string.force_encoding('utf-8')
|
|
64
|
-
output = JSON.parse(output)
|
|
65
|
-
LibTangram.tangram_string_free(output_ptr.read_pointer)
|
|
66
|
-
output
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def log_prediction(identifier:, options: nil, input:, output:)
|
|
70
|
-
self.log_event(self.prediction_event(identifier, options, input, output))
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def enqueue_log_prediction(identifier:, options: nil, input:, output:)
|
|
74
|
-
self.log_queue.push(self.prediction_event(identifier, options, input, output))
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def log_true_value(identifier:, true_value:)
|
|
78
|
-
self.log_event(self.true_value_event(identifier, true_value))
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def enqueue_log_true_value(identifier:, true_value:)
|
|
82
|
-
self.log_queue.push(self.true_value_event(identifier, true_value))
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def flush_log_queue()
|
|
86
|
-
self.log_events(@log_queue)
|
|
87
|
-
@log_queue = []
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def log_event(event)
|
|
91
|
-
self.log_events([event])
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def log_events(events)
|
|
95
|
-
if @token.nil?
|
|
96
|
-
raise 'Tangram cannot log events without a token. Make sure to pass a token to the model constructor.'
|
|
97
|
-
end
|
|
98
|
-
headers = {
|
|
99
|
-
'Content-Type': 'application/json',
|
|
100
|
-
'Authorization': 'Bearer ' + @token,
|
|
101
|
-
}
|
|
102
|
-
uri = URI(@base_url + '/api/track')
|
|
103
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
|
104
|
-
request = Net::HTTP::Post.new(uri.request_uri, headers)
|
|
105
|
-
request.body = events.to_json
|
|
106
|
-
response = http.request(request)
|
|
107
|
-
unless response.kind_of? Net::HTTPSuccess
|
|
108
|
-
raise response
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def prediction_event(identifier:, options: nil, input:, output:)
|
|
113
|
-
return {
|
|
114
|
-
type: 'prediction',
|
|
115
|
-
modelId: self.id,
|
|
116
|
-
identifier: identifier,
|
|
117
|
-
options: options,
|
|
118
|
-
input: input,
|
|
119
|
-
output: output,
|
|
120
|
-
}
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def true_value_event(identifier:, true_value:)
|
|
124
|
-
return {
|
|
125
|
-
type: 'true_value',
|
|
126
|
-
modelId: self.id,
|
|
127
|
-
identifier: identifier,
|
|
128
|
-
trueValue: true_value,
|
|
129
|
-
}
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
end
|
|
133
|
-
end
|
|
Binary file
|