opentelemetry-api 0.16.0 → 1.0.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +57 -0
- data/README.md +3 -3
- data/lib/opentelemetry.rb +21 -28
- data/lib/opentelemetry/baggage.rb +95 -2
- data/lib/opentelemetry/baggage/builder.rb +30 -4
- data/lib/opentelemetry/baggage/entry.rb +20 -0
- data/lib/opentelemetry/baggage/propagation.rb +9 -18
- data/lib/opentelemetry/baggage/propagation/text_map_propagator.rb +111 -0
- data/lib/opentelemetry/context.rb +48 -33
- data/lib/opentelemetry/context/propagation.rb +35 -5
- data/lib/opentelemetry/context/propagation/composite_text_map_propagator.rb +105 -0
- data/lib/opentelemetry/context/propagation/noop_text_map_propagator.rb +27 -0
- data/lib/opentelemetry/context/propagation/{propagator.rb → text_map_propagator.rb} +23 -16
- data/lib/opentelemetry/internal.rb +17 -0
- data/lib/opentelemetry/internal/proxy_tracer.rb +38 -0
- data/lib/opentelemetry/internal/proxy_tracer_provider.rb +59 -0
- data/lib/opentelemetry/trace.rb +10 -0
- data/lib/opentelemetry/trace/propagation/trace_context.rb +7 -18
- data/lib/opentelemetry/trace/propagation/trace_context/text_map_propagator.rb +73 -0
- data/lib/opentelemetry/trace/status.rb +34 -5
- data/lib/opentelemetry/trace/tracer.rb +8 -9
- data/lib/opentelemetry/version.rb +1 -1
- metadata +16 -25
- data/lib/opentelemetry/baggage/manager.rb +0 -41
- data/lib/opentelemetry/baggage/propagation/text_map_extractor.rb +0 -57
- data/lib/opentelemetry/baggage/propagation/text_map_injector.rb +0 -52
- data/lib/opentelemetry/context/propagation/composite_propagator.rb +0 -72
- data/lib/opentelemetry/context/propagation/noop_extractor.rb +0 -26
- data/lib/opentelemetry/context/propagation/noop_injector.rb +0 -26
- data/lib/opentelemetry/instrumentation.rb +0 -15
- data/lib/opentelemetry/instrumentation/base.rb +0 -307
- data/lib/opentelemetry/instrumentation/registry.rb +0 -86
- data/lib/opentelemetry/metrics.rb +0 -16
- data/lib/opentelemetry/metrics/handles.rb +0 -44
- data/lib/opentelemetry/metrics/instruments.rb +0 -105
- data/lib/opentelemetry/metrics/meter.rb +0 -72
- data/lib/opentelemetry/metrics/meter_provider.rb +0 -22
- data/lib/opentelemetry/trace/propagation/trace_context/text_map_extractor.rb +0 -52
- data/lib/opentelemetry/trace/propagation/trace_context/text_map_injector.rb +0 -49
- data/lib/opentelemetry/trace/util/http_to_status.rb +0 -28
@@ -1,86 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright The OpenTelemetry Authors
|
4
|
-
#
|
5
|
-
# SPDX-License-Identifier: Apache-2.0
|
6
|
-
|
7
|
-
module OpenTelemetry
|
8
|
-
module Instrumentation
|
9
|
-
# The instrumentation Registry contains information about instrumentation
|
10
|
-
# available and facilitates discovery, installation and
|
11
|
-
# configuration. This functionality is primarily useful for SDK
|
12
|
-
# implementors.
|
13
|
-
class Registry
|
14
|
-
def initialize
|
15
|
-
@lock = Mutex.new
|
16
|
-
@instrumentation = []
|
17
|
-
end
|
18
|
-
|
19
|
-
# @api private
|
20
|
-
def register(instrumentation)
|
21
|
-
@lock.synchronize do
|
22
|
-
@instrumentation << instrumentation
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# Lookup an instrumentation definition by name. Returns nil if +instrumentation_name+
|
27
|
-
# is not found.
|
28
|
-
#
|
29
|
-
# @param [String] instrumentation_name A stringified class name for an instrumentation
|
30
|
-
# @return [Instrumentation]
|
31
|
-
def lookup(instrumentation_name)
|
32
|
-
@lock.synchronize do
|
33
|
-
find_instrumentation(instrumentation_name)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# Install the specified instrumentation with optionally specified configuration.
|
38
|
-
#
|
39
|
-
# @param [Array<String>] instrumentation_names An array of instrumentation names to
|
40
|
-
# install
|
41
|
-
# @param [optional Hash<String, Hash>] instrumentation_config_map A map of
|
42
|
-
# instrumentation_name to config. This argument is optional and config can be
|
43
|
-
# passed for as many or as few instrumentations as desired.
|
44
|
-
def install(instrumentation_names, instrumentation_config_map = {})
|
45
|
-
@lock.synchronize do
|
46
|
-
instrumentation_names.each do |instrumentation_name|
|
47
|
-
instrumentation = find_instrumentation(instrumentation_name)
|
48
|
-
OpenTelemetry.logger.warn "Could not install #{instrumentation_name} because it was not found" unless instrumentation
|
49
|
-
|
50
|
-
install_instrumentation(instrumentation, instrumentation_config_map[instrumentation.name])
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# Install all instrumentation available and installable in this process.
|
56
|
-
#
|
57
|
-
# @param [optional Hash<String, Hash>] instrumentation_config_map A map of
|
58
|
-
# instrumentation_name to config. This argument is optional and config can be
|
59
|
-
# passed for as many or as few instrumentations as desired.
|
60
|
-
def install_all(instrumentation_config_map = {})
|
61
|
-
@lock.synchronize do
|
62
|
-
@instrumentation.map(&:instance).each do |instrumentation|
|
63
|
-
install_instrumentation(instrumentation, instrumentation_config_map[instrumentation.name])
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
def find_instrumentation(instrumentation_name)
|
71
|
-
@instrumentation.detect { |a| a.instance.name == instrumentation_name }
|
72
|
-
&.instance
|
73
|
-
end
|
74
|
-
|
75
|
-
def install_instrumentation(instrumentation, config)
|
76
|
-
if instrumentation.install(config)
|
77
|
-
OpenTelemetry.logger.info "Instrumentation: #{instrumentation.name} was successfully installed"
|
78
|
-
else
|
79
|
-
OpenTelemetry.logger.warn "Instrumentation: #{instrumentation.name} failed to install"
|
80
|
-
end
|
81
|
-
rescue => e # rubocop:disable Style/RescueStandardError
|
82
|
-
OpenTelemetry.handle_error(exception: e, message: "Instrumentation: #{instrumentation.name} unhandled exception during install: #{e.backtrace}")
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright The OpenTelemetry Authors
|
4
|
-
#
|
5
|
-
# SPDX-License-Identifier: Apache-2.0
|
6
|
-
|
7
|
-
require 'opentelemetry/metrics/handles'
|
8
|
-
require 'opentelemetry/metrics/instruments'
|
9
|
-
require 'opentelemetry/metrics/meter'
|
10
|
-
require 'opentelemetry/metrics/meter_provider'
|
11
|
-
|
12
|
-
module OpenTelemetry
|
13
|
-
# The Metrics API allows reporting raw measurements as well as metrics with known aggregation and labels.
|
14
|
-
module Metrics
|
15
|
-
end
|
16
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright The OpenTelemetry Authors
|
4
|
-
#
|
5
|
-
# SPDX-License-Identifier: Apache-2.0
|
6
|
-
|
7
|
-
module OpenTelemetry
|
8
|
-
module Metrics
|
9
|
-
# In situations where performance is a requirement and a metric is
|
10
|
-
# repeatedly used with the same labels, the developer may elect to
|
11
|
-
# use instrument {Handles} as an optimization. For handles to be a benefit,
|
12
|
-
# it requires that a specific instrument will be re-used with specific
|
13
|
-
# labels. If an instrument will be used with the same labels more than
|
14
|
-
# once, obtaining an instrument handle corresponding to the labels
|
15
|
-
# ensures the highest performance available.
|
16
|
-
#
|
17
|
-
# To obtain a handle given an instrument and labels, use the #handle
|
18
|
-
# method to return an interface that supports the #add or #record
|
19
|
-
# method of the instrument in question.
|
20
|
-
#
|
21
|
-
# Instrument handles may consume SDK resources indefinitely.
|
22
|
-
module Handles
|
23
|
-
# A float counter handle.
|
24
|
-
class FloatCounter
|
25
|
-
def add(value); end
|
26
|
-
end
|
27
|
-
|
28
|
-
# An integer counter handle.
|
29
|
-
class IntegerCounter
|
30
|
-
def add(value); end
|
31
|
-
end
|
32
|
-
|
33
|
-
# A float measure handle.
|
34
|
-
class FloatMeasure
|
35
|
-
def record(value); end
|
36
|
-
end
|
37
|
-
|
38
|
-
# An integer measure handle.
|
39
|
-
class IntegerMeasure
|
40
|
-
def record(value); end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,105 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright The OpenTelemetry Authors
|
4
|
-
#
|
5
|
-
# SPDX-License-Identifier: Apache-2.0
|
6
|
-
|
7
|
-
module OpenTelemetry
|
8
|
-
module Metrics
|
9
|
-
# The user-facing metrics API supports producing diagnostic measurements
|
10
|
-
# using three basic kinds of instrument. "Metrics" are the thing being
|
11
|
-
# produced -- mathematical, statistical summaries of certain observable
|
12
|
-
# behavior in the program. "Instruments" are the devices used by the
|
13
|
-
# program to record observations about their behavior. Therefore, we use
|
14
|
-
# "metric instrument" to refer to a program object, allocated through the
|
15
|
-
# API, used for recording metrics. There are three distinct instruments in
|
16
|
-
# the Metrics API, commonly known as Counters, Observers, and Measures.
|
17
|
-
module Instruments
|
18
|
-
# TODO: Observers.
|
19
|
-
|
20
|
-
# A float counter instrument.
|
21
|
-
class FloatCounter
|
22
|
-
def add(value, labels = {}); end
|
23
|
-
|
24
|
-
# Obtain a handle from the instrument and labels.
|
25
|
-
#
|
26
|
-
# @param [optional Hash<String, String>] labels A Hash of Strings.
|
27
|
-
# @return [Handles::FloatCounter]
|
28
|
-
def handle(labels = {})
|
29
|
-
Handles::FloatCounter.new
|
30
|
-
end
|
31
|
-
|
32
|
-
# Return a measurement to be recorded via {Meter#record_batch}.
|
33
|
-
#
|
34
|
-
# @param [Float] value
|
35
|
-
# @return [Object, Measurement]
|
36
|
-
def measurement(value)
|
37
|
-
NOOP_MEASUREMENT
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# An integer counter instrument.
|
42
|
-
class IntegerCounter
|
43
|
-
def add(value, labels = {}); end
|
44
|
-
|
45
|
-
# Obtain a handle from the instrument and labels.
|
46
|
-
#
|
47
|
-
# @param [optional Hash<String, String>] labels A Hash of Strings.
|
48
|
-
# @return [Handles::IntegerCounter]
|
49
|
-
def handle(labels = {})
|
50
|
-
Handles::IntegerCounter.new
|
51
|
-
end
|
52
|
-
|
53
|
-
# Return a measurement to be recorded via {Meter#record_batch}.
|
54
|
-
#
|
55
|
-
# @param [Integer] value
|
56
|
-
# @return [Object, Measurement]
|
57
|
-
def measurement(value)
|
58
|
-
NOOP_MEASUREMENT
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# A float measure instrument.
|
63
|
-
class FloatMeasure
|
64
|
-
def record(value, labels = {}); end
|
65
|
-
|
66
|
-
# Obtain a handle from the instrument and labels.
|
67
|
-
#
|
68
|
-
# @param [optional Hash<String, String>] labels A Hash of Strings.
|
69
|
-
# @return [Handles::FloatMeasure]
|
70
|
-
def handle(labels = {})
|
71
|
-
Handles::FloatMeasure.new
|
72
|
-
end
|
73
|
-
|
74
|
-
# Return a measurement to be recorded via {Meter#record_batch}.
|
75
|
-
#
|
76
|
-
# @param [Float] value
|
77
|
-
# @return [Object, Measurement]
|
78
|
-
def measurement(value)
|
79
|
-
NOOP_MEASUREMENT
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
# An integer measure instrument.
|
84
|
-
class IntegerMeasure
|
85
|
-
def record(value, labels = {}); end
|
86
|
-
|
87
|
-
# Obtain a handle from the instrument and labels.
|
88
|
-
#
|
89
|
-
# @param [optional Hash<String, String>] labels A Hash of Strings.
|
90
|
-
# @return [Handles::IntegerMeasure]
|
91
|
-
def handle(labels = {})
|
92
|
-
Handles::IntegerMeasure.new
|
93
|
-
end
|
94
|
-
|
95
|
-
# Return a measurement to be recorded via {Meter#record_batch}.
|
96
|
-
#
|
97
|
-
# @param [Integer] value
|
98
|
-
# @return [Object, Measurement]
|
99
|
-
def measurement(value)
|
100
|
-
NOOP_MEASUREMENT
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright The OpenTelemetry Authors
|
4
|
-
#
|
5
|
-
# SPDX-License-Identifier: Apache-2.0
|
6
|
-
|
7
|
-
module OpenTelemetry
|
8
|
-
module Metrics
|
9
|
-
# No-op implementation of Meter.
|
10
|
-
class Meter
|
11
|
-
def record_batch(*measurements, labels: nil); end
|
12
|
-
|
13
|
-
# TODO: Observers.
|
14
|
-
|
15
|
-
# Create and return a floating point counter.
|
16
|
-
#
|
17
|
-
# @param [String] name Name of the metric. See {Meter} for required metric name syntax.
|
18
|
-
# @param [optional String] description Descriptive text documenting the instrument.
|
19
|
-
# @param [optional String] unit Unit specified according to http://unitsofmeasure.org/ucum.html.
|
20
|
-
# @param [optional Enumerable<String>] recommended_label_keys Recommended grouping keys for this instrument.
|
21
|
-
# @param [optional Boolean] monotonic Whether the counter accepts only monotonic updates. Defaults to true.
|
22
|
-
# @return [FloatCounter]
|
23
|
-
def create_float_counter(name, description: nil, unit: nil, recommended_label_keys: nil, monotonic: true)
|
24
|
-
raise ArgumentError if name.nil?
|
25
|
-
|
26
|
-
Instruments::FloatCounter.new
|
27
|
-
end
|
28
|
-
|
29
|
-
# Create and return an integer counter.
|
30
|
-
#
|
31
|
-
# @param [String] name Name of the metric. See {Meter} for required metric name syntax.
|
32
|
-
# @param [optional String] description Descriptive text documenting the instrument.
|
33
|
-
# @param [optional String] unit Unit specified according to http://unitsofmeasure.org/ucum.html.
|
34
|
-
# @param [optional Enumerable<String>] recommended_label_keys Recommended grouping keys for this instrument.
|
35
|
-
# @param [optional Boolean] monotonic Whether the counter accepts only monotonic updates. Defaults to true.
|
36
|
-
# @return [IntegerCounter]
|
37
|
-
def create_integer_counter(name, description: nil, unit: nil, recommended_label_keys: nil, monotonic: true)
|
38
|
-
raise ArgumentError if name.nil?
|
39
|
-
|
40
|
-
Instruments::IntegerCounter.new
|
41
|
-
end
|
42
|
-
|
43
|
-
# Create and return a floating point measure.
|
44
|
-
#
|
45
|
-
# @param [String] name Name of the metric. See {Meter} for required metric name syntax.
|
46
|
-
# @param [optional String] description Descriptive text documenting the instrument.
|
47
|
-
# @param [optional String] unit Unit specified according to http://unitsofmeasure.org/ucum.html.
|
48
|
-
# @param [optional Enumerable<String>] recommended_label_keys Recommended grouping keys for this instrument.
|
49
|
-
# @param [optional Boolean] absolute Whether the measure accepts only non-negative updates. Defaults to true.
|
50
|
-
# @return [FloatMeasure]
|
51
|
-
def create_float_measure(name, description: nil, unit: nil, recommended_label_keys: nil, absolute: true)
|
52
|
-
raise ArgumentError if name.nil?
|
53
|
-
|
54
|
-
Instruments::FloatMeasure.new
|
55
|
-
end
|
56
|
-
|
57
|
-
# Create and return an integer measure.
|
58
|
-
#
|
59
|
-
# @param [String] name Name of the metric. See {Meter} for required metric name syntax.
|
60
|
-
# @param [optional String] description Descriptive text documenting the instrument.
|
61
|
-
# @param [optional String] unit Unit specified according to http://unitsofmeasure.org/ucum.html.
|
62
|
-
# @param [optional Enumerable<String>] recommended_label_keys Recommended grouping keys for this instrument.
|
63
|
-
# @param [optional Boolean] absolute Whether the measure accepts only non-negative updates. Defaults to true.
|
64
|
-
# @return [IntegerMeasure]
|
65
|
-
def create_integer_measure(name, description: nil, unit: nil, recommended_label_keys: nil, absolute: true)
|
66
|
-
raise ArgumentError if name.nil?
|
67
|
-
|
68
|
-
Instruments::IntegerMeasure.new
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright The OpenTelemetry Authors
|
4
|
-
#
|
5
|
-
# SPDX-License-Identifier: Apache-2.0
|
6
|
-
|
7
|
-
module OpenTelemetry
|
8
|
-
module Metrics
|
9
|
-
# No-op implementation of a meter provider.
|
10
|
-
class MeterProvider
|
11
|
-
# Returns a {Meter} instance.
|
12
|
-
#
|
13
|
-
# @param [optional String] name Instrumentation package name
|
14
|
-
# @param [optional String] version Instrumentation package version
|
15
|
-
#
|
16
|
-
# @return [Meter]
|
17
|
-
def meter(name = nil, version = nil)
|
18
|
-
@meter ||= Meter.new
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright The OpenTelemetry Authors
|
4
|
-
#
|
5
|
-
# SPDX-License-Identifier: Apache-2.0
|
6
|
-
module OpenTelemetry
|
7
|
-
module Trace
|
8
|
-
module Propagation
|
9
|
-
module TraceContext
|
10
|
-
# Extracts context from carriers in the W3C Trace Context format
|
11
|
-
class TextMapExtractor
|
12
|
-
# Returns a new TextMapExtractor that extracts context using the
|
13
|
-
# specified getter
|
14
|
-
#
|
15
|
-
# @param [optional Getter] default_getter The default getter used to read
|
16
|
-
# headers from a carrier during extract. Defaults to a +TextMapGetter+
|
17
|
-
# instance.
|
18
|
-
# @return [TextMapExtractor]
|
19
|
-
def initialize(default_getter = Context::Propagation.text_map_getter)
|
20
|
-
@default_getter = default_getter
|
21
|
-
end
|
22
|
-
|
23
|
-
# Extract a remote {Trace::SpanContext} from the supplied carrier.
|
24
|
-
# Invalid headers will result in a new, valid, non-remote {Trace::SpanContext}.
|
25
|
-
#
|
26
|
-
# @param [Carrier] carrier The carrier to get the header from.
|
27
|
-
# @param [Context] context The context to be updated with extracted context
|
28
|
-
# @param [optional Getter] getter If the optional getter is provided, it
|
29
|
-
# will be used to read the header from the carrier, otherwise the default
|
30
|
-
# getter will be used.
|
31
|
-
# @return [Context] Updated context with span context from the header, or the original
|
32
|
-
# context if parsing fails.
|
33
|
-
def extract(carrier, context, getter = nil)
|
34
|
-
getter ||= @default_getter
|
35
|
-
tp = TraceParent.from_string(getter.get(carrier, TRACEPARENT_KEY))
|
36
|
-
tracestate = Tracestate.from_string(getter.get(carrier, TRACESTATE_KEY))
|
37
|
-
|
38
|
-
span_context = Trace::SpanContext.new(trace_id: tp.trace_id,
|
39
|
-
span_id: tp.span_id,
|
40
|
-
trace_flags: tp.flags,
|
41
|
-
tracestate: tracestate,
|
42
|
-
remote: true)
|
43
|
-
span = Trace::Span.new(span_context: span_context)
|
44
|
-
OpenTelemetry::Trace.context_with_span(span)
|
45
|
-
rescue OpenTelemetry::Error
|
46
|
-
context
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright The OpenTelemetry Authors
|
4
|
-
#
|
5
|
-
# SPDX-License-Identifier: Apache-2.0
|
6
|
-
module OpenTelemetry
|
7
|
-
module Trace
|
8
|
-
module Propagation
|
9
|
-
module TraceContext
|
10
|
-
# Injects context into carriers using the W3C Trace Context format
|
11
|
-
class TextMapInjector
|
12
|
-
# Returns a new TextMapInjector that injects context using the
|
13
|
-
# specified setter
|
14
|
-
#
|
15
|
-
# @param [optional Setter] default_setter The default setter used to
|
16
|
-
# write context into a carrier during inject. Defaults to a
|
17
|
-
# {TextMapSetter} instance.
|
18
|
-
# @return [TextMapInjector]
|
19
|
-
def initialize(default_setter = Context::Propagation.text_map_setter)
|
20
|
-
@default_setter = default_setter
|
21
|
-
end
|
22
|
-
|
23
|
-
# Set the span context on the supplied carrier.
|
24
|
-
#
|
25
|
-
# @param [Context] context The active {Context}.
|
26
|
-
# @param [optional Setter] setter If the optional setter is provided, it
|
27
|
-
# will be used to write context into the carrier, otherwise the default
|
28
|
-
# setter will be used.
|
29
|
-
# @return [Object] the carrier with context injected
|
30
|
-
def inject(carrier, context, setter = nil)
|
31
|
-
return carrier unless (span_context = span_context_from(context))
|
32
|
-
|
33
|
-
setter ||= @default_setter
|
34
|
-
setter.set(carrier, TRACEPARENT_KEY, TraceParent.from_span_context(span_context).to_s)
|
35
|
-
setter.set(carrier, TRACESTATE_KEY, span_context.tracestate.to_s) unless span_context.tracestate.empty?
|
36
|
-
|
37
|
-
carrier
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def span_context_from(context)
|
43
|
-
OpenTelemetry::Trace.current_span(context).context
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|