microsoft-agents-a365-observability-core 0.2.1.dev7__tar.gz → 0.2.1.dev10__tar.gz
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.
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/PKG-INFO +1 -1
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/__init__.py +11 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/config.py +7 -3
- microsoft_agents_a365_observability_core-0.2.1.dev10/microsoft_agents_a365/observability/core/exporters/enriched_span.py +160 -0
- microsoft_agents_a365_observability_core-0.2.1.dev10/microsoft_agents_a365/observability/core/exporters/enriching_span_processor.py +86 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365_observability_core.egg-info/PKG-INFO +1 -1
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365_observability_core.egg-info/SOURCES.txt +2 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/README.md +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/agent_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/constants.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/execute_tool_scope.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/execution_type.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/exporters/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/exporters/agent365_exporter.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/exporters/agent365_exporter_options.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/exporters/utils.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/inference_call_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/inference_operation_type.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/inference_scope.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/invoke_agent_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/invoke_agent_scope.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/middleware/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/middleware/baggage_builder.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/models/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/models/agent_type.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/models/caller_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/models/operation_source.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/opentelemetry_scope.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/request.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/source_metadata.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/tenant_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/tool_call_details.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/tool_type.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/trace_processor/__init__.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/trace_processor/span_processor.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/trace_processor/util.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365/observability/core/utils.py +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365_observability_core.egg-info/dependency_links.txt +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365_observability_core.egg-info/requires.txt +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/microsoft_agents_a365_observability_core.egg-info/top_level.txt +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/pyproject.toml +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/setup.cfg +0 -0
- {microsoft_agents_a365_observability_core-0.2.1.dev7 → microsoft_agents_a365_observability_core-0.2.1.dev10}/setup.py +0 -0
|
@@ -12,6 +12,12 @@ from .config import (
|
|
|
12
12
|
)
|
|
13
13
|
from .execute_tool_scope import ExecuteToolScope
|
|
14
14
|
from .execution_type import ExecutionType
|
|
15
|
+
from .exporters.enriched_span import EnrichedReadableSpan
|
|
16
|
+
from .exporters.enriching_span_processor import (
|
|
17
|
+
get_span_enricher,
|
|
18
|
+
register_span_enricher,
|
|
19
|
+
unregister_span_enricher,
|
|
20
|
+
)
|
|
15
21
|
from .inference_call_details import InferenceCallDetails
|
|
16
22
|
from .inference_operation_type import InferenceOperationType
|
|
17
23
|
from .inference_scope import InferenceScope
|
|
@@ -32,6 +38,11 @@ __all__ = [
|
|
|
32
38
|
"is_configured",
|
|
33
39
|
"get_tracer",
|
|
34
40
|
"get_tracer_provider",
|
|
41
|
+
# Span enrichment
|
|
42
|
+
"register_span_enricher",
|
|
43
|
+
"unregister_span_enricher",
|
|
44
|
+
"get_span_enricher",
|
|
45
|
+
"EnrichedReadableSpan",
|
|
35
46
|
# Span processor
|
|
36
47
|
"SpanProcessor",
|
|
37
48
|
# Base scope class
|
|
@@ -9,10 +9,13 @@ from typing import Any, Optional
|
|
|
9
9
|
from opentelemetry import trace
|
|
10
10
|
from opentelemetry.sdk.resources import SERVICE_NAME, SERVICE_NAMESPACE, Resource
|
|
11
11
|
from opentelemetry.sdk.trace import TracerProvider
|
|
12
|
-
from opentelemetry.sdk.trace.export import
|
|
12
|
+
from opentelemetry.sdk.trace.export import ConsoleSpanExporter
|
|
13
13
|
|
|
14
14
|
from .exporters.agent365_exporter import _Agent365Exporter
|
|
15
15
|
from .exporters.agent365_exporter_options import Agent365ExporterOptions
|
|
16
|
+
from .exporters.enriching_span_processor import (
|
|
17
|
+
_EnrichingBatchSpanProcessor,
|
|
18
|
+
)
|
|
16
19
|
from .exporters.utils import is_agent365_exporter_enabled
|
|
17
20
|
from .trace_processor.span_processor import SpanProcessor
|
|
18
21
|
|
|
@@ -166,8 +169,9 @@ class TelemetryManager:
|
|
|
166
169
|
|
|
167
170
|
# Add span processors
|
|
168
171
|
|
|
169
|
-
# Create
|
|
170
|
-
|
|
172
|
+
# Create _EnrichingBatchSpanProcessor with optimized settings
|
|
173
|
+
# This allows extensions to enrich spans before export
|
|
174
|
+
batch_processor = _EnrichingBatchSpanProcessor(exporter, **batch_processor_kwargs)
|
|
171
175
|
agent_processor = SpanProcessor()
|
|
172
176
|
|
|
173
177
|
tracer_provider.add_span_processor(batch_processor)
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
"""Enriched ReadableSpan wrapper for adding attributes to immutable spans."""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from opentelemetry.sdk.trace import ReadableSpan
|
|
10
|
+
from opentelemetry.util import types
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class EnrichedReadableSpan(ReadableSpan):
|
|
14
|
+
"""
|
|
15
|
+
Wrapper to add attributes to an immutable ReadableSpan.
|
|
16
|
+
|
|
17
|
+
Since ReadableSpan is immutable after a span ends, this wrapper allows
|
|
18
|
+
extensions to add additional attributes before export without modifying
|
|
19
|
+
the original span.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, span: ReadableSpan, extra_attributes: dict):
|
|
23
|
+
"""
|
|
24
|
+
Initialize the enriched span wrapper.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
span: The original ReadableSpan to wrap.
|
|
28
|
+
extra_attributes: Additional attributes to merge with the original.
|
|
29
|
+
"""
|
|
30
|
+
self._span = span
|
|
31
|
+
self._extra_attributes = extra_attributes
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def attributes(self) -> types.Attributes:
|
|
35
|
+
"""Return merged attributes from original span and extra attributes."""
|
|
36
|
+
original = dict(self._span.attributes or {})
|
|
37
|
+
original.update(self._extra_attributes)
|
|
38
|
+
return original
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def name(self):
|
|
42
|
+
"""Return the span name."""
|
|
43
|
+
return self._span.name
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def context(self):
|
|
47
|
+
"""Return the span context."""
|
|
48
|
+
return self._span.context
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def parent(self):
|
|
52
|
+
"""Return the parent span context."""
|
|
53
|
+
return self._span.parent
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def start_time(self):
|
|
57
|
+
"""Return the span start time."""
|
|
58
|
+
return self._span.start_time
|
|
59
|
+
|
|
60
|
+
@property
|
|
61
|
+
def end_time(self):
|
|
62
|
+
"""Return the span end time."""
|
|
63
|
+
return self._span.end_time
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def status(self):
|
|
67
|
+
"""Return the span status."""
|
|
68
|
+
return self._span.status
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def kind(self):
|
|
72
|
+
"""Return the span kind."""
|
|
73
|
+
return self._span.kind
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def events(self):
|
|
77
|
+
"""Return the span events."""
|
|
78
|
+
return self._span.events
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def links(self):
|
|
82
|
+
"""Return the span links."""
|
|
83
|
+
return self._span.links
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def resource(self):
|
|
87
|
+
"""Return the span resource."""
|
|
88
|
+
return self._span.resource
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def instrumentation_scope(self):
|
|
92
|
+
"""Return the instrumentation scope."""
|
|
93
|
+
return self._span.instrumentation_scope
|
|
94
|
+
|
|
95
|
+
def to_json(self, indent: int | None = 4) -> str:
|
|
96
|
+
"""
|
|
97
|
+
Convert span to JSON string with enriched attributes.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
indent: JSON indentation level.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
JSON string representation of the span.
|
|
104
|
+
"""
|
|
105
|
+
# Build the JSON dict manually to include enriched attributes
|
|
106
|
+
return json.dumps(
|
|
107
|
+
{
|
|
108
|
+
"name": self.name,
|
|
109
|
+
"context": {
|
|
110
|
+
"trace_id": f"0x{self.context.trace_id:032x}",
|
|
111
|
+
"span_id": f"0x{self.context.span_id:016x}",
|
|
112
|
+
"trace_state": str(self.context.trace_state),
|
|
113
|
+
}
|
|
114
|
+
if self.context
|
|
115
|
+
else None,
|
|
116
|
+
"kind": str(self.kind),
|
|
117
|
+
"parent_id": f"0x{self.parent.span_id:016x}" if self.parent else None,
|
|
118
|
+
"start_time": self._format_time(self.start_time),
|
|
119
|
+
"end_time": self._format_time(self.end_time),
|
|
120
|
+
"status": {
|
|
121
|
+
"status_code": str(self.status.status_code),
|
|
122
|
+
"description": self.status.description,
|
|
123
|
+
}
|
|
124
|
+
if self.status
|
|
125
|
+
else None,
|
|
126
|
+
"attributes": dict(self.attributes) if self.attributes else None,
|
|
127
|
+
"events": [self._format_event(e) for e in self.events] if self.events else None,
|
|
128
|
+
"links": [self._format_link(lnk) for lnk in self.links] if self.links else None,
|
|
129
|
+
"resource": dict(self.resource.attributes) if self.resource else None,
|
|
130
|
+
},
|
|
131
|
+
indent=indent,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
def _format_time(self, time_ns: int | None) -> str | None:
|
|
135
|
+
"""Format nanosecond timestamp to ISO string."""
|
|
136
|
+
if time_ns is None:
|
|
137
|
+
return None
|
|
138
|
+
from datetime import datetime, timezone
|
|
139
|
+
|
|
140
|
+
return datetime.fromtimestamp(time_ns / 1e9, tz=timezone.utc).isoformat()
|
|
141
|
+
|
|
142
|
+
def _format_event(self, event: Any) -> dict:
|
|
143
|
+
"""Format a span event."""
|
|
144
|
+
return {
|
|
145
|
+
"name": event.name,
|
|
146
|
+
"timestamp": self._format_time(event.timestamp),
|
|
147
|
+
"attributes": dict(event.attributes) if event.attributes else None,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
def _format_link(self, link: Any) -> dict:
|
|
151
|
+
"""Format a span link."""
|
|
152
|
+
return {
|
|
153
|
+
"context": {
|
|
154
|
+
"trace_id": f"0x{link.context.trace_id:032x}",
|
|
155
|
+
"span_id": f"0x{link.context.span_id:016x}",
|
|
156
|
+
}
|
|
157
|
+
if link.context
|
|
158
|
+
else None,
|
|
159
|
+
"attributes": dict(link.attributes) if link.attributes else None,
|
|
160
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
"""Span enrichment support for the Agent365 exporter pipeline."""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
import threading
|
|
8
|
+
from collections.abc import Callable
|
|
9
|
+
|
|
10
|
+
from opentelemetry.sdk.trace import ReadableSpan
|
|
11
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
# Single span enricher - only one platform instrumentor should be active at a time
|
|
16
|
+
_span_enricher: Callable[[ReadableSpan], ReadableSpan] | None = None
|
|
17
|
+
_enricher_lock = threading.Lock()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def register_span_enricher(enricher: Callable[[ReadableSpan], ReadableSpan]) -> None:
|
|
21
|
+
"""Register the span enricher for the active platform instrumentor.
|
|
22
|
+
|
|
23
|
+
Only one enricher can be registered at a time since auto-instrumentation
|
|
24
|
+
is platform-specific (Semantic Kernel, LangChain, or OpenAI Agents).
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
enricher: Function that takes a ReadableSpan and returns an enriched span.
|
|
28
|
+
|
|
29
|
+
Raises:
|
|
30
|
+
RuntimeError: If an enricher is already registered.
|
|
31
|
+
"""
|
|
32
|
+
global _span_enricher
|
|
33
|
+
with _enricher_lock:
|
|
34
|
+
if _span_enricher is not None:
|
|
35
|
+
raise RuntimeError(
|
|
36
|
+
"A span enricher is already registered. "
|
|
37
|
+
"Only one platform instrumentor can be active at a time."
|
|
38
|
+
)
|
|
39
|
+
_span_enricher = enricher
|
|
40
|
+
logger.debug("Span enricher registered: %s", enricher.__name__)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def unregister_span_enricher() -> None:
|
|
44
|
+
"""Unregister the current span enricher.
|
|
45
|
+
|
|
46
|
+
Called during uninstrumentation to clean up.
|
|
47
|
+
"""
|
|
48
|
+
global _span_enricher
|
|
49
|
+
with _enricher_lock:
|
|
50
|
+
if _span_enricher is not None:
|
|
51
|
+
logger.debug("Span enricher unregistered: %s", _span_enricher.__name__)
|
|
52
|
+
_span_enricher = None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_span_enricher() -> Callable[[ReadableSpan], ReadableSpan] | None:
|
|
56
|
+
"""Get the currently registered span enricher.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
The registered enricher function, or None if no enricher is registered.
|
|
60
|
+
"""
|
|
61
|
+
with _enricher_lock:
|
|
62
|
+
return _span_enricher
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class _EnrichingBatchSpanProcessor(BatchSpanProcessor):
|
|
66
|
+
"""BatchSpanProcessor that applies the registered enricher before batching."""
|
|
67
|
+
|
|
68
|
+
def on_end(self, span: ReadableSpan) -> None:
|
|
69
|
+
"""Apply the span enricher and pass to parent for batching.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
span: The span that has ended.
|
|
73
|
+
"""
|
|
74
|
+
enriched_span = span
|
|
75
|
+
|
|
76
|
+
enricher = get_span_enricher()
|
|
77
|
+
if enricher is not None:
|
|
78
|
+
try:
|
|
79
|
+
enriched_span = enricher(span)
|
|
80
|
+
except Exception:
|
|
81
|
+
logger.exception(
|
|
82
|
+
"Span enricher %s raised an exception, using original span",
|
|
83
|
+
enricher.__name__,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
super().on_end(enriched_span)
|
|
@@ -22,6 +22,8 @@ microsoft_agents_a365/observability/core/utils.py
|
|
|
22
22
|
microsoft_agents_a365/observability/core/exporters/__init__.py
|
|
23
23
|
microsoft_agents_a365/observability/core/exporters/agent365_exporter.py
|
|
24
24
|
microsoft_agents_a365/observability/core/exporters/agent365_exporter_options.py
|
|
25
|
+
microsoft_agents_a365/observability/core/exporters/enriched_span.py
|
|
26
|
+
microsoft_agents_a365/observability/core/exporters/enriching_span_processor.py
|
|
25
27
|
microsoft_agents_a365/observability/core/exporters/utils.py
|
|
26
28
|
microsoft_agents_a365/observability/core/middleware/__init__.py
|
|
27
29
|
microsoft_agents_a365/observability/core/middleware/baggage_builder.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|