diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 80f99eb94..059fce23c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -53,6 +53,6 @@ repos: rev: v2.3.0 hooks: - id: codespell - args: ['--skip', 'tests/models/cassettes/*'] + args: ['--skip', 'tests/models/cassettes/*', '--skip', 'tests/models/test_cohere.py'] additional_dependencies: - tomli diff --git a/docs/thinking.md b/docs/thinking.md new file mode 100644 index 000000000..fac3d02b9 --- /dev/null +++ b/docs/thinking.md @@ -0,0 +1,3 @@ +# Thinking + +Also known as reasoning, "thinking" is the process of using a model's capabilities to reason about a task. diff --git a/mkdocs.yml b/mkdocs.yml index 02cf3e703..55a1a7e06 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -38,6 +38,7 @@ nav: - graph.md - evals.md - input.md + - thinking.md - MCP: - mcp/index.md - mcp/client.md diff --git a/pydantic_ai_slim/pydantic_ai/_agent_graph.py b/pydantic_ai_slim/pydantic_ai/_agent_graph.py index 9ce7091a7..0b9c6fd96 100644 --- a/pydantic_ai_slim/pydantic_ai/_agent_graph.py +++ b/pydantic_ai_slim/pydantic_ai/_agent_graph.py @@ -397,7 +397,7 @@ async def stream( async for _event in stream: pass - async def _run_stream( + async def _run_stream( # noqa: C901 self, ctx: GraphRunContext[GraphAgentState, GraphAgentDeps[DepsT, NodeRunEndT]] ) -> AsyncIterator[_messages.HandleResponseEvent]: if self._events_iterator is None: @@ -413,6 +413,12 @@ async def _run_stream() -> AsyncIterator[_messages.HandleResponseEvent]: texts.append(part.content) elif isinstance(part, _messages.ToolCallPart): tool_calls.append(part) + elif isinstance(part, _messages.ThinkingPart): + # We don't need to do anything with thinking parts in this tool-calling node. + # We need to handle text parts in case there are no tool calls and/or the desired output comes + # from the text, but thinking parts should not directly influence the execution of tools or + # determination of the next node of graph execution here. + pass else: assert_never(part) diff --git a/pydantic_ai_slim/pydantic_ai/_parts_manager.py b/pydantic_ai_slim/pydantic_ai/_parts_manager.py index 0471f0d59..d010c7eff 100644 --- a/pydantic_ai_slim/pydantic_ai/_parts_manager.py +++ b/pydantic_ai_slim/pydantic_ai/_parts_manager.py @@ -25,6 +25,8 @@ PartStartEvent, TextPart, TextPartDelta, + ThinkingPart, + ThinkingPartDelta, ToolCallPart, ToolCallPartDelta, ) @@ -86,8 +88,7 @@ def handle_text_delta( A `PartStartEvent` if a new part was created, or a `PartDeltaEvent` if an existing part was updated. Raises: - UnexpectedModelBehavior: If attempting to apply text content to a part that is - not a TextPart. + UnexpectedModelBehavior: If attempting to apply text content to a part that is not a TextPart. """ existing_text_part_and_index: tuple[TextPart, int] | None = None @@ -122,6 +123,77 @@ def handle_text_delta( self._parts[part_index] = part_delta.apply(existing_text_part) return PartDeltaEvent(index=part_index, delta=part_delta) + def handle_thinking_delta( + self, + *, + vendor_part_id: Hashable | None, + content: str | None = None, + signature: str | None = None, + ) -> ModelResponseStreamEvent: + """Handle incoming thinking content, creating or updating a ThinkingPart in the manager as appropriate. + + When `vendor_part_id` is None, the latest part is updated if it exists and is a ThinkingPart; + otherwise, a new ThinkingPart is created. When a non-None ID is specified, the ThinkingPart corresponding + to that vendor ID is either created or updated. + + Args: + vendor_part_id: The ID the vendor uses to identify this piece + of thinking. If None, a new part will be created unless the latest part is already + a ThinkingPart. + content: The thinking content to append to the appropriate ThinkingPart. + signature: An optional signature for the thinking content. + + Returns: + A `PartStartEvent` if a new part was created, or a `PartDeltaEvent` if an existing part was updated. + + Raises: + UnexpectedModelBehavior: If attempting to apply a thinking delta to a part that is not a ThinkingPart. + """ + existing_thinking_part_and_index: tuple[ThinkingPart, int] | None = None + + if vendor_part_id is None: + # If the vendor_part_id is None, check if the latest part is a ThinkingPart to update + if self._parts: + part_index = len(self._parts) - 1 + latest_part = self._parts[part_index] + if isinstance(latest_part, ThinkingPart): + existing_thinking_part_and_index = latest_part, part_index + else: + # Otherwise, attempt to look up an existing ThinkingPart by vendor_part_id + part_index = self._vendor_id_to_part_index.get(vendor_part_id) + if part_index is not None: + existing_part = self._parts[part_index] + if not isinstance(existing_part, ThinkingPart): + raise UnexpectedModelBehavior(f'Cannot apply a thinking delta to {existing_part=}') + existing_thinking_part_and_index = existing_part, part_index + + if existing_thinking_part_and_index is None: + if content is not None: + # There is no existing thinking part that should be updated, so create a new one + new_part_index = len(self._parts) + part = ThinkingPart(content=content, signature=signature) + if vendor_part_id is not None: + self._vendor_id_to_part_index[vendor_part_id] = new_part_index + self._parts.append(part) + return PartStartEvent(index=new_part_index, part=part) + else: + raise UnexpectedModelBehavior('Cannot create a ThinkingPart with no content') + else: + if content is not None: + # Update the existing ThinkingPart with the new content delta + existing_thinking_part, part_index = existing_thinking_part_and_index + part_delta = ThinkingPartDelta(content_delta=content) + self._parts[part_index] = part_delta.apply(existing_thinking_part) + return PartDeltaEvent(index=part_index, delta=part_delta) + elif signature is not None: + # Update the existing ThinkingPart with the new signature delta + existing_thinking_part, part_index = existing_thinking_part_and_index + part_delta = ThinkingPartDelta(signature_delta=signature) + self._parts[part_index] = part_delta.apply(existing_thinking_part) + return PartDeltaEvent(index=part_index, delta=part_delta) + else: + raise UnexpectedModelBehavior('Cannot update a ThinkingPart with no content or signature') + def handle_tool_call_delta( self, *, diff --git a/pydantic_ai_slim/pydantic_ai/_thinking_part.py b/pydantic_ai_slim/pydantic_ai/_thinking_part.py new file mode 100644 index 000000000..5e24cbc3f --- /dev/null +++ b/pydantic_ai_slim/pydantic_ai/_thinking_part.py @@ -0,0 +1,32 @@ +from __future__ import annotations as _annotations + +from pydantic_ai.messages import TextPart, ThinkingPart + +START_THINK_TAG = '' +END_THINK_TAG = '' + + +def split_content_into_text_and_thinking(content: str) -> list[ThinkingPart | TextPart]: + """Split a string into text and thinking parts. + + Some models don't return the thinking part as a separate part, but rather as a tag in the content. + This function splits the content into text and thinking parts. + + We use the `` tag because that's how Groq uses it in the `raw` format, so instead of using `` or + something else, we just match the tag to make it easier for other models that don't support the `ThinkingPart`. + """ + parts: list[ThinkingPart | TextPart] = [] + while START_THINK_TAG in content: + before_think, content = content.split(START_THINK_TAG, 1) + if before_think.strip(): + parts.append(TextPart(content=before_think)) + if END_THINK_TAG in content: + think_content, content = content.split(END_THINK_TAG, 1) + parts.append(ThinkingPart(content=think_content)) + else: + # We lose the `` tag, but it shouldn't matter. + parts.append(TextPart(content=content)) + content = '' + if content: + parts.append(TextPart(content=content)) + return parts diff --git a/pydantic_ai_slim/pydantic_ai/messages.py b/pydantic_ai_slim/pydantic_ai/messages.py index 48eb82f65..c708114ec 100644 --- a/pydantic_ai_slim/pydantic_ai/messages.py +++ b/pydantic_ai_slim/pydantic_ai/messages.py @@ -486,6 +486,24 @@ def has_content(self) -> bool: return bool(self.content) +@dataclass +class ThinkingPart: + """A thinking response from a model.""" + + content: str + """The thinking content of the response.""" + + signature: str | None = None + """The signature of the thinking.""" + + part_kind: Literal['thinking'] = 'thinking' + """Part type identifier, this is available on all parts as a discriminator.""" + + def has_content(self) -> bool: + """Return `True` if the thinking content is non-empty.""" + return bool(self.content) + + @dataclass class ToolCallPart: """A tool call from a model.""" @@ -540,7 +558,7 @@ def has_content(self) -> bool: return bool(self.args) -ModelResponsePart = Annotated[Union[TextPart, ToolCallPart], pydantic.Discriminator('part_kind')] +ModelResponsePart = Annotated[Union[TextPart, ToolCallPart, ThinkingPart], pydantic.Discriminator('part_kind')] """A message part returned by a model.""" @@ -630,6 +648,54 @@ def apply(self, part: ModelResponsePart) -> TextPart: return replace(part, content=part.content + self.content_delta) +@dataclass +class ThinkingPartDelta: + """A partial update (delta) for a `ThinkingPart` to append new thinking content.""" + + content_delta: str | None = None + """The incremental thinking content to add to the existing `ThinkingPart` content.""" + + signature_delta: str | None = None + """Optional signature delta. + + Note this is never treated as a delta — it can replace None. + """ + + part_delta_kind: Literal['thinking'] = 'thinking' + """Part delta type identifier, used as a discriminator.""" + + @overload + def apply(self, part: ModelResponsePart) -> ThinkingPart: ... + + @overload + def apply(self, part: ModelResponsePart | ThinkingPartDelta) -> ThinkingPart | ThinkingPartDelta: ... + + def apply(self, part: ModelResponsePart | ThinkingPartDelta) -> ThinkingPart | ThinkingPartDelta: + """Apply this thinking delta to an existing `ThinkingPart`. + + Args: + part: The existing model response part, which must be a `ThinkingPart`. + + Returns: + A new `ThinkingPart` with updated thinking content. + + Raises: + ValueError: If `part` is not a `ThinkingPart`. + """ + if isinstance(part, ThinkingPart): + return replace(part, content=part.content + self.content_delta if self.content_delta else None) + elif isinstance(part, ThinkingPartDelta): + if self.content_delta is None and self.signature_delta is None: + raise ValueError('Cannot apply ThinkingPartDelta with no content or signature') + if self.signature_delta is not None: + return replace(part, signature_delta=self.signature_delta) + if self.content_delta is not None: + return replace(part, content_delta=self.content_delta) + raise ValueError( + f'Cannot apply ThinkingPartDeltas to non-ThinkingParts or non-ThinkingPartDeltas ({part=}, {self=})' + ) + + @dataclass class ToolCallPartDelta: """A partial update (delta) for a `ToolCallPart` to modify tool name, arguments, or tool call ID.""" @@ -745,7 +811,9 @@ def _apply_to_part(self, part: ToolCallPart) -> ToolCallPart: return part -ModelResponsePartDelta = Annotated[Union[TextPartDelta, ToolCallPartDelta], pydantic.Discriminator('part_delta_kind')] +ModelResponsePartDelta = Annotated[ + Union[TextPartDelta, ThinkingPartDelta, ToolCallPartDelta], pydantic.Discriminator('part_delta_kind') +] """A partial update (delta) for any model response part.""" diff --git a/pydantic_ai_slim/pydantic_ai/models/anthropic.py b/pydantic_ai_slim/pydantic_ai/models/anthropic.py index 61156849e..e567cc3b3 100644 --- a/pydantic_ai_slim/pydantic_ai/models/anthropic.py +++ b/pydantic_ai_slim/pydantic_ai/models/anthropic.py @@ -1,6 +1,7 @@ from __future__ import annotations as _annotations import io +import warnings from collections.abc import AsyncGenerator, AsyncIterable, AsyncIterator from contextlib import asynccontextmanager from dataclasses import dataclass, field @@ -24,6 +25,7 @@ RetryPromptPart, SystemPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, UserPromptPart, @@ -58,9 +60,15 @@ RawMessageStartEvent, RawMessageStopEvent, RawMessageStreamEvent, + RedactedThinkingBlock, + SignatureDelta, TextBlock, TextBlockParam, TextDelta, + ThinkingBlock, + ThinkingBlockParam, + ThinkingConfigParam, + ThinkingDelta, ToolChoiceParam, ToolParam, ToolResultBlockParam, @@ -90,7 +98,7 @@ """ -class AnthropicModelSettings(ModelSettings): +class AnthropicModelSettings(ModelSettings, total=False): """Settings used for an Anthropic model request. ALL FIELDS MUST BE `anthropic_` PREFIXED SO YOU CAN MERGE THEM WITH OTHER MODELS. @@ -99,7 +107,14 @@ class AnthropicModelSettings(ModelSettings): anthropic_metadata: MetadataParam """An object describing metadata about the request. - Contains `user_id`, an external identifier for the user who is associated with the request.""" + Contains `user_id`, an external identifier for the user who is associated with the request. + """ + + anthropic_thinking: ThinkingConfigParam + """Determine whether the model should generate a thinking block. + + See [the Anthropic docs](https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking) for more information. + """ @dataclass(init=False) @@ -109,10 +124,6 @@ class AnthropicModel(Model): Internally, this uses the [Anthropic Python client](https://github.com/anthropics/anthropic-sdk-python) to interact with the API. Apart from `__init__`, all methods are private or match those of the base class. - - !!! note - The `AnthropicModel` class does not yet support streaming responses. - We anticipate adding support for streaming responses in a near-term future release. """ client: AsyncAnthropic = field(repr=False) @@ -226,13 +237,14 @@ async def _messages_create( try: return await self.client.messages.create( - max_tokens=model_settings.get('max_tokens', 1024), + max_tokens=model_settings.get('max_tokens', 2048), system=system_prompt or NOT_GIVEN, messages=anthropic_messages, model=self._model_name, tools=tools or NOT_GIVEN, tool_choice=tool_choice or NOT_GIVEN, stream=stream, + thinking=model_settings.get('anthropic_thinking', NOT_GIVEN), stop_sequences=model_settings.get('stop_sequences', NOT_GIVEN), temperature=model_settings.get('temperature', NOT_GIVEN), top_p=model_settings.get('top_p', NOT_GIVEN), @@ -252,6 +264,14 @@ def _process_response(self, response: AnthropicMessage) -> ModelResponse: for item in response.content: if isinstance(item, TextBlock): items.append(TextPart(content=item.text)) + elif isinstance(item, RedactedThinkingBlock): # pragma: no cover + warnings.warn( + 'PydanticAI currently does not handle redacted thinking blocks. ' + 'If you have a suggestion on how we should handle them, please open an issue.', + UserWarning, + ) + elif isinstance(item, ThinkingBlock): + items.append(ThinkingPart(content=item.thinking, signature=item.signature)) else: assert isinstance(item, ToolUseBlock), 'unexpected item type' items.append( @@ -318,10 +338,17 @@ async def _map_message(self, messages: list[ModelMessage]) -> tuple[str, list[Me user_content_params.append(retry_param) anthropic_messages.append(MessageParam(role='user', content=user_content_params)) elif isinstance(m, ModelResponse): - assistant_content_params: list[TextBlockParam | ToolUseBlockParam] = [] + assistant_content_params: list[TextBlockParam | ToolUseBlockParam | ThinkingBlockParam] = [] for response_part in m.parts: if isinstance(response_part, TextPart): assistant_content_params.append(TextBlockParam(text=response_part.content, type='text')) + elif isinstance(response_part, ThinkingPart): + assert response_part.signature is not None, 'Thinking part must have a signature' + assistant_content_params.append( + ThinkingBlockParam( + thinking=response_part.content, signature=response_part.signature, type='thinking' + ) + ) else: tool_use_block_param = ToolUseBlockParam( id=_guard_tool_call_id(t=response_part), @@ -438,6 +465,12 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: current_block = event.content_block if isinstance(current_block, TextBlock) and current_block.text: yield self._parts_manager.handle_text_delta(vendor_part_id='content', content=current_block.text) + elif isinstance(current_block, ThinkingBlock): + yield self._parts_manager.handle_thinking_delta( + vendor_part_id='thinking', + content=current_block.thinking, + signature=current_block.signature, + ) elif isinstance(current_block, ToolUseBlock): maybe_event = self._parts_manager.handle_tool_call_delta( vendor_part_id=current_block.id, @@ -451,6 +484,14 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: elif isinstance(event, RawContentBlockDeltaEvent): if isinstance(event.delta, TextDelta): yield self._parts_manager.handle_text_delta(vendor_part_id='content', content=event.delta.text) + elif isinstance(event.delta, ThinkingDelta): + yield self._parts_manager.handle_thinking_delta( + vendor_part_id='thinking', content=event.delta.thinking + ) + elif isinstance(event.delta, SignatureDelta): + yield self._parts_manager.handle_thinking_delta( + vendor_part_id='thinking', signature=event.delta.signature + ) elif ( current_block and event.delta.type == 'input_json_delta' and isinstance(current_block, ToolUseBlock) ): diff --git a/pydantic_ai_slim/pydantic_ai/models/bedrock.py b/pydantic_ai_slim/pydantic_ai/models/bedrock.py index a8882ba62..f9e1a66ad 100644 --- a/pydantic_ai_slim/pydantic_ai/models/bedrock.py +++ b/pydantic_ai_slim/pydantic_ai/models/bedrock.py @@ -2,6 +2,7 @@ import functools import typing +import warnings from collections.abc import AsyncIterator, Iterable, Iterator, Mapping from contextlib import asynccontextmanager from dataclasses import dataclass, field @@ -27,6 +28,7 @@ RetryPromptPart, SystemPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, UserPromptPart, @@ -252,11 +254,16 @@ async def _process_response(self, response: ConverseResponseTypeDef) -> tuple[Mo items: list[ModelResponsePart] = [] if message := response['output'].get('message'): for item in message['content']: + if reasoning_content := item.get('reasoningContent'): + reasoning_text = reasoning_content.get('reasoningText') + if reasoning_text: + thinking_part = ThinkingPart(content=reasoning_text['text']) + if reasoning_signature := reasoning_text.get('signature'): + thinking_part.signature = reasoning_signature + items.append(thinking_part) if text := item.get('text'): items.append(TextPart(content=text)) - else: - tool_use = item.get('toolUse') - assert tool_use is not None, f'Found a content that is not a text or tool use: {item}' + elif tool_use := item.get('toolUse'): items.append( ToolCallPart( tool_name=tool_use['name'], @@ -419,6 +426,9 @@ async def _map_messages( for item in m.parts: if isinstance(item, TextPart): content.append({'text': item.content}) + elif isinstance(item, ThinkingPart): + # NOTE: We don't pass the thinking part to Bedrock since it raises an error. + pass else: assert isinstance(item, ToolCallPart) content.append(self._map_tool_call(item)) @@ -532,6 +542,15 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: if 'contentBlockDelta' in chunk: index = chunk['contentBlockDelta']['contentBlockIndex'] delta = chunk['contentBlockDelta']['delta'] + if 'reasoningContent' in delta: + if text := delta['reasoningContent'].get('text'): + yield self._parts_manager.handle_thinking_delta(vendor_part_id=index, content=text) + else: # pragma: no cover + warnings.warn( + f'Only text reasoning content is supported yet, but you got {delta["reasoningContent"]}. ' + 'Please report this to the maintainers.', + UserWarning, + ) if 'text' in delta: yield self._parts_manager.handle_text_delta(vendor_part_id=index, content=delta['text']) if 'toolUse' in delta: diff --git a/pydantic_ai_slim/pydantic_ai/models/cohere.py b/pydantic_ai_slim/pydantic_ai/models/cohere.py index c4017958c..3c9be22fb 100644 --- a/pydantic_ai_slim/pydantic_ai/models/cohere.py +++ b/pydantic_ai_slim/pydantic_ai/models/cohere.py @@ -6,6 +6,8 @@ from typing_extensions import assert_never +from pydantic_ai._thinking_part import split_content_into_text_and_thinking + from .. import ModelHTTPError, usage from .._utils import generate_tool_call_id as _generate_tool_call_id, guard_tool_call_id as _guard_tool_call_id from ..messages import ( @@ -16,6 +18,7 @@ RetryPromptPart, SystemPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, UserPromptPart, @@ -181,7 +184,7 @@ def _process_response(self, response: ChatResponse) -> ModelResponse: # While Cohere's API returns a list, it only does that for future proofing # and currently only one item is being returned. choice = response.message.content[0] - parts.append(TextPart(choice.text)) + parts.extend(split_content_into_text_and_thinking(choice.text)) for c in response.message.tool_calls or []: if c.function and c.function.name and c.function.arguments: parts.append( @@ -205,6 +208,8 @@ def _map_messages(self, messages: list[ModelMessage]) -> list[ChatMessageV2]: for item in message.parts: if isinstance(item, TextPart): texts.append(item.content) + elif isinstance(item, ThinkingPart): + texts.append(f'\n{item.content}\n') elif isinstance(item, ToolCallPart): tool_calls.append(self._map_tool_call(item)) else: diff --git a/pydantic_ai_slim/pydantic_ai/models/function.py b/pydantic_ai_slim/pydantic_ai/models/function.py index de57f1d42..79324b549 100644 --- a/pydantic_ai_slim/pydantic_ai/models/function.py +++ b/pydantic_ai_slim/pydantic_ai/models/function.py @@ -24,6 +24,7 @@ RetryPromptPart, SystemPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, UserContent, @@ -263,7 +264,7 @@ def _estimate_usage(messages: Iterable[ModelMessage]) -> usage.Usage: assert_never(part) elif isinstance(message, ModelResponse): for part in message.parts: - if isinstance(part, TextPart): + if isinstance(part, (TextPart, ThinkingPart)): response_tokens += _estimate_string_tokens(part.content) elif isinstance(part, ToolCallPart): call = part diff --git a/pydantic_ai_slim/pydantic_ai/models/gemini.py b/pydantic_ai_slim/pydantic_ai/models/gemini.py index 0dedb5291..0657004f0 100644 --- a/pydantic_ai_slim/pydantic_ai/models/gemini.py +++ b/pydantic_ai_slim/pydantic_ai/models/gemini.py @@ -30,6 +30,7 @@ RetryPromptPart, SystemPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, UserPromptPart, @@ -73,7 +74,7 @@ """ -class GeminiModelSettings(ModelSettings): +class GeminiModelSettings(ModelSettings, total=False): """Settings used for a Gemini model request. ALL FIELDS MUST BE `gemini_` PREFIXED SO YOU CAN MERGE THEM WITH OTHER MODELS. @@ -81,6 +82,15 @@ class GeminiModelSettings(ModelSettings): gemini_safety_settings: list[GeminiSafetySettings] + gemini_thinking_config: ThinkingConfig + """Thinking is on by default in both the API and AI Studio. + + Being on by default doesn't mean the model will send back thoughts. For that, you need to set `include_thoughts` + to `True`. If you want to turn it off, set `thinking_budget` to `0`. + + See more about it on . + """ + @dataclass(init=False) class GeminiModel(Model): @@ -223,7 +233,9 @@ async def _make_request( generation_config['presence_penalty'] = presence_penalty if (frequency_penalty := model_settings.get('frequency_penalty')) is not None: generation_config['frequency_penalty'] = frequency_penalty - if (gemini_safety_settings := model_settings.get('gemini_safety_settings')) != []: + if (thinkingConfig := model_settings.get('gemini_thinking_config')) is not None: + generation_config['thinking_config'] = thinkingConfig + if (gemini_safety_settings := model_settings.get('gemini_safety_settings')) is not None: request_data['safetySettings'] = gemini_safety_settings if generation_config: request_data['generationConfig'] = generation_config @@ -499,6 +511,16 @@ class GeminiSafetySettings(TypedDict): """ +class ThinkingConfig(TypedDict, total=False): + """The thinking features configuration.""" + + include_thoughts: Annotated[bool, pydantic.Field(alias='includeThoughts')] + """Indicates whether to include thoughts in the response. If true, thoughts are returned only if the model supports thought and thoughts are available.""" + + thinking_budget: Annotated[int, pydantic.Field(alias='thinkingBudget')] + """Indicates the thinking budget in tokens.""" + + class _GeminiGenerationConfig(TypedDict, total=False): """Schema for an API request to the Gemini API. @@ -513,6 +535,7 @@ class _GeminiGenerationConfig(TypedDict, total=False): presence_penalty: float frequency_penalty: float stop_sequences: list[str] + thinking_config: ThinkingConfig class _GeminiContent(TypedDict): @@ -525,6 +548,8 @@ def _content_model_response(m: ModelResponse) -> _GeminiContent: for item in m.parts: if isinstance(item, ToolCallPart): parts.append(_function_call_part_from_call(item)) + elif isinstance(item, ThinkingPart): + parts.append(_GeminiTextPart(text=item.content, thought=True)) elif isinstance(item, TextPart): if item.content: parts.append(_GeminiTextPart(text=item.content)) @@ -533,33 +558,38 @@ def _content_model_response(m: ModelResponse) -> _GeminiContent: return _GeminiContent(role='model', parts=parts) -class _GeminiTextPart(TypedDict): +class _BasePart(TypedDict): + thought: NotRequired[bool] + """Indicates if the part is thought from the model.""" + + +class _GeminiTextPart(_BasePart): text: str -class _GeminiInlineData(TypedDict): +class _GeminiInlineData(_BasePart): data: str mime_type: Annotated[str, pydantic.Field(alias='mimeType')] -class _GeminiInlineDataPart(TypedDict): +class _GeminiInlineDataPart(_BasePart): """See .""" inline_data: Annotated[_GeminiInlineData, pydantic.Field(alias='inlineData')] -class _GeminiFileData(TypedDict): +class _GeminiFileData(_BasePart): """See .""" file_uri: Annotated[str, pydantic.Field(alias='fileUri')] mime_type: Annotated[str, pydantic.Field(alias='mimeType')] -class _GeminiFileDataPart(TypedDict): +class _GeminiFileDataPart(_BasePart): file_data: Annotated[_GeminiFileData, pydantic.Field(alias='fileData')] -class _GeminiFunctionCallPart(TypedDict): +class _GeminiFunctionCallPart(_BasePart): function_call: Annotated[_GeminiFunctionCall, pydantic.Field(alias='functionCall')] @@ -573,7 +603,12 @@ def _process_response_from_parts( items: list[ModelResponsePart] = [] for part in parts: if 'text' in part: - items.append(TextPart(content=part['text'])) + # NOTE: Google doesn't include the `thought` field anymore. We handle this here in case they decide to + # change their mind and start including it again. + if part.get('thought'): # pragma: no cover + items.append(ThinkingPart(content=part['text'])) + else: + items.append(TextPart(content=part['text'])) elif 'function_call' in part: items.append(ToolCallPart(tool_name=part['function_call']['name'], args=part['function_call']['args'])) elif 'function_response' in part: diff --git a/pydantic_ai_slim/pydantic_ai/models/groq.py b/pydantic_ai_slim/pydantic_ai/models/groq.py index 7559e8851..bb9d644aa 100644 --- a/pydantic_ai_slim/pydantic_ai/models/groq.py +++ b/pydantic_ai_slim/pydantic_ai/models/groq.py @@ -9,6 +9,8 @@ from typing_extensions import assert_never +from pydantic_ai._thinking_part import split_content_into_text_and_thinking + from .. import ModelHTTPError, UnexpectedModelBehavior, _utils, usage from .._utils import guard_tool_call_id as _guard_tool_call_id from ..messages import ( @@ -23,6 +25,7 @@ RetryPromptPart, SystemPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, UserPromptPart, @@ -82,13 +85,13 @@ """ -class GroqModelSettings(ModelSettings): +class GroqModelSettings(ModelSettings, total=False): """Settings used for a Groq model request. ALL FIELDS MUST BE `groq_` PREFIXED SO YOU CAN MERGE THEM WITH OTHER MODELS. """ - # This class is a placeholder for any future groq-specific settings + groq_reasoning_format: Literal['hidden', 'raw', 'parsed'] @dataclass(init=False) @@ -215,6 +218,7 @@ async def _completions_create( timeout=model_settings.get('timeout', NOT_GIVEN), seed=model_settings.get('seed', NOT_GIVEN), presence_penalty=model_settings.get('presence_penalty', NOT_GIVEN), + reasoning_format=model_settings.get('groq_reasoning_format', NOT_GIVEN), frequency_penalty=model_settings.get('frequency_penalty', NOT_GIVEN), logit_bias=model_settings.get('logit_bias', NOT_GIVEN), extra_headers={'User-Agent': get_user_agent()}, @@ -230,8 +234,12 @@ def _process_response(self, response: chat.ChatCompletion) -> ModelResponse: timestamp = datetime.fromtimestamp(response.created, tz=timezone.utc) choice = response.choices[0] items: list[ModelResponsePart] = [] + # NOTE: The `reasoning` field is only present if `groq_reasoning_format` is set to `parsed`. + if choice.message.reasoning is not None: + items.append(ThinkingPart(content=choice.message.reasoning)) if choice.message.content is not None: - items.append(TextPart(content=choice.message.content)) + # NOTE: The `` tag is only present if `groq_reasoning_format` is set to `raw`. + items.extend(split_content_into_text_and_thinking(choice.message.content)) if choice.message.tool_calls is not None: for c in choice.message.tool_calls: items.append(ToolCallPart(tool_name=c.function.name, args=c.function.arguments, tool_call_id=c.id)) @@ -270,6 +278,9 @@ def _map_messages(self, messages: list[ModelMessage]) -> list[chat.ChatCompletio texts.append(item.content) elif isinstance(item, ToolCallPart): tool_calls.append(self._map_tool_call(item)) + elif isinstance(item, ThinkingPart): + # Skip thinking parts when mapping to Groq messages + continue else: assert_never(item) message_param = chat.ChatCompletionAssistantMessageParam(role='assistant') diff --git a/pydantic_ai_slim/pydantic_ai/models/mistral.py b/pydantic_ai_slim/pydantic_ai/models/mistral.py index 8bff0a76f..0ec3a63a9 100644 --- a/pydantic_ai_slim/pydantic_ai/models/mistral.py +++ b/pydantic_ai_slim/pydantic_ai/models/mistral.py @@ -11,6 +11,8 @@ from httpx import Timeout from typing_extensions import assert_never +from pydantic_ai._thinking_part import split_content_into_text_and_thinking + from .. import ModelHTTPError, UnexpectedModelBehavior, _utils from .._utils import generate_tool_call_id as _generate_tool_call_id, now_utc as _now_utc from ..messages import ( @@ -25,6 +27,7 @@ RetryPromptPart, SystemPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, UserPromptPart, @@ -91,7 +94,7 @@ """ -class MistralModelSettings(ModelSettings): +class MistralModelSettings(ModelSettings, total=False): """Settings used for a Mistral model request. ALL FIELDS MUST BE `mistral_` PREFIXED SO YOU CAN MERGE THEM WITH OTHER MODELS. @@ -316,7 +319,7 @@ def _process_response(self, response: MistralChatCompletionResponse) -> ModelRes parts: list[ModelResponsePart] = [] if text := _map_content(content): - parts.append(TextPart(content=text)) + parts.extend(split_content_into_text_and_thinking(text)) if isinstance(tool_calls, list): for tool_call in tool_calls: @@ -474,6 +477,8 @@ def _map_messages(self, messages: list[ModelMessage]) -> list[MistralMessages]: for part in message.parts: if isinstance(part, TextPart): content_chunks.append(MistralTextChunk(text=part.content)) + elif isinstance(part, ThinkingPart): + content_chunks.append(MistralTextChunk(text=f'{part.content}')) elif isinstance(part, ToolCallPart): tool_calls.append(self._map_tool_call(part)) else: diff --git a/pydantic_ai_slim/pydantic_ai/models/openai.py b/pydantic_ai_slim/pydantic_ai/models/openai.py index 8047db80f..6c8f19f33 100644 --- a/pydantic_ai_slim/pydantic_ai/models/openai.py +++ b/pydantic_ai_slim/pydantic_ai/models/openai.py @@ -11,6 +11,7 @@ from typing_extensions import assert_never +from pydantic_ai._thinking_part import split_content_into_text_and_thinking from pydantic_ai.providers import Provider, infer_provider from .. import ModelHTTPError, UnexpectedModelBehavior, _utils, usage @@ -28,6 +29,7 @@ RetryPromptPart, SystemPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, UserPromptPart, @@ -60,6 +62,7 @@ from openai.types.chat.chat_completion_content_part_param import File, FileFile from openai.types.responses import ComputerToolParam, FileSearchToolParam, WebSearchToolParam from openai.types.responses.response_input_param import FunctionCallOutput, Message + from openai.types.responses.response_reasoning_item_param import Summary from openai.types.shared import ReasoningEffort from openai.types.shared_params import Reasoning except ImportError as _import_error: @@ -124,6 +127,9 @@ class OpenAIResponsesModelSettings(OpenAIModelSettings, total=False): """ openai_reasoning_generate_summary: Literal['detailed', 'concise'] + """Deprecated alias for `openai_reasoning_summary`.""" + + openai_reasoning_summary: Literal['detailed', 'concise'] """A summary of the reasoning performed by the model. This can be useful for debugging and understanding the model's reasoning process. @@ -297,8 +303,11 @@ def _process_response(self, response: chat.ChatCompletion) -> ModelResponse: timestamp = datetime.fromtimestamp(response.created, tz=timezone.utc) choice = response.choices[0] items: list[ModelResponsePart] = [] + # The `reasoning_content` is only present in DeepSeek models. + if reasoning_content := getattr(choice.message, 'reasoning_content', None): + items.append(ThinkingPart(content=reasoning_content)) if choice.message.content is not None: - items.append(TextPart(choice.message.content)) + items.extend(split_content_into_text_and_thinking(choice.message.content)) if choice.message.tool_calls is not None: for c in choice.message.tool_calls: items.append(ToolCallPart(c.function.name, c.function.arguments, tool_call_id=c.id)) @@ -336,6 +345,8 @@ async def _map_messages(self, messages: list[ModelMessage]) -> list[chat.ChatCom for item in message.parts: if isinstance(item, TextPart): texts.append(item.content) + elif isinstance(item, ThinkingPart): + texts.append(f'\n{item.content}\n') elif isinstance(item, ToolCallPart): tool_calls.append(self._map_tool_call(item)) else: @@ -550,7 +561,12 @@ def _process_response(self, response: responses.Response) -> ModelResponse: items: list[ModelResponsePart] = [] items.append(TextPart(response.output_text)) for item in response.output: - if item.type == 'function_call': + if item.type == 'reasoning': + for summary in item.summary: + # NOTE: We use the same id for all summaries because we can merge them on the round trip. + # The providers don't force the signature to be unique. + items.append(ThinkingPart(content=summary.text, signature=item.id)) + elif item.type == 'function_call': items.append(ToolCallPart(item.name, item.arguments, tool_call_id=item.call_id)) return ModelResponse(items, model_name=response.model, timestamp=timestamp) @@ -635,11 +651,22 @@ async def _responses_create( def _get_reasoning(self, model_settings: OpenAIResponsesModelSettings) -> Reasoning | NotGiven: reasoning_effort = model_settings.get('openai_reasoning_effort', None) + reasoning_summary = model_settings.get('openai_reasoning_summary', None) reasoning_generate_summary = model_settings.get('openai_reasoning_generate_summary', None) - if reasoning_effort is None and reasoning_generate_summary is None: + if reasoning_summary and reasoning_generate_summary: # pragma: no cover + raise ValueError('`openai_reasoning_summary` and `openai_reasoning_generate_summary` cannot both be set.') + + if reasoning_generate_summary is not None: # pragma: no cover + warnings.warn( + '`openai_reasoning_generate_summary` is deprecated, use `openai_reasoning_summary` instead', + DeprecationWarning, + ) + reasoning_summary = reasoning_generate_summary + + if reasoning_effort is None and reasoning_summary is None: return NOT_GIVEN - return Reasoning(effort=reasoning_effort, generate_summary=reasoning_generate_summary) + return Reasoning(effort=reasoning_effort, summary=reasoning_summary) def _get_tools(self, model_request_parameters: ModelRequestParameters) -> list[responses.FunctionToolParam]: tools = [self._map_tool_definition(r) for r in model_request_parameters.function_tools] @@ -658,7 +685,7 @@ def _map_tool_definition(f: ToolDefinition) -> responses.FunctionToolParam: 'strict': f.strict or False, } - async def _map_messages( + async def _map_messages( # noqa: C901 self, messages: list[ModelMessage] ) -> tuple[str | NotGiven, list[responses.ResponseInputItemParam]]: """Just maps a `pydantic_ai.Message` to a `openai.types.responses.ResponseInputParam`.""" @@ -695,13 +722,33 @@ async def _map_messages( else: assert_never(part) elif isinstance(message, ModelResponse): + last_thinking_part_idx: int | None = None for item in message.parts: if isinstance(item, TextPart): openai_messages.append(responses.EasyInputMessageParam(role='assistant', content=item.content)) elif isinstance(item, ToolCallPart): openai_messages.append(self._map_tool_call(item)) + elif isinstance(item, ThinkingPart): + assert item.signature is not None, 'If this is triggered, please create an issue.' + if last_thinking_part_idx is not None: + reasoning_item = cast(responses.ResponseReasoningItemParam, openai_messages[last_thinking_part_idx]) # fmt: skip + if item.signature == reasoning_item['id']: + assert isinstance(reasoning_item['summary'], list) + reasoning_item['summary'].append(Summary(text=item.content, type='summary_text')) + continue + last_thinking_part_idx = len(openai_messages) + openai_messages.append( + responses.ResponseReasoningItemParam( + id=item.signature, + summary=[Summary(text=item.content, type='summary_text')], + type='reasoning', + ) + ) else: assert_never(item) + from rich.pretty import pprint + + pprint(openai_messages) else: assert_never(message) instructions = self._get_instructions(messages) or NOT_GIVEN @@ -839,6 +886,9 @@ class OpenAIResponsesStreamedResponse(StreamedResponse): async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: # noqa: C901 async for chunk in self._response: + from rich.pretty import pprint + + pprint(chunk) if isinstance(chunk, responses.ResponseCompletedEvent): self._usage += _map_usage(chunk.response) @@ -879,13 +929,40 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: vendor_part_id=chunk.item.id, tool_name=chunk.item.name, args=chunk.item.arguments, - tool_call_id=chunk.item.id, + tool_call_id=chunk.item.call_id, + ) + elif isinstance(chunk.item, responses.ResponseReasoningItem): + content = chunk.item.summary[0].text if chunk.item.summary else '' + yield self._parts_manager.handle_thinking_delta( + vendor_part_id=chunk.item.id, + content=content, + signature=chunk.item.id, ) + elif isinstance(chunk.item, responses.ResponseOutputMessage): + pass + else: + raise RuntimeError(f'Unexpected item type: {type(chunk.item)}') elif isinstance(chunk, responses.ResponseOutputItemDoneEvent): # NOTE: We only need this if the tool call deltas don't include the final info. pass + elif isinstance(chunk, responses.ResponseReasoningSummaryPartAddedEvent): + pass # there's nothing we need to do here + + elif isinstance(chunk, responses.ResponseReasoningSummaryPartDoneEvent): + pass # there's nothing we need to do here + + elif isinstance(chunk, responses.ResponseReasoningSummaryTextDoneEvent): + pass # there's nothing we need to do here + + elif isinstance(chunk, responses.ResponseReasoningSummaryTextDeltaEvent): + yield self._parts_manager.handle_thinking_delta( + vendor_part_id=chunk.item_id, + content=chunk.delta, + signature=chunk.item_id, + ) + elif isinstance(chunk, responses.ResponseTextDeltaEvent): yield self._parts_manager.handle_text_delta(vendor_part_id=chunk.content_index, content=chunk.delta) diff --git a/pydantic_ai_slim/pydantic_ai/models/test.py b/pydantic_ai_slim/pydantic_ai/models/test.py index 5f2982f71..cdac5bf28 100644 --- a/pydantic_ai_slim/pydantic_ai/models/test.py +++ b/pydantic_ai_slim/pydantic_ai/models/test.py @@ -9,6 +9,7 @@ from typing import Any, Literal import pydantic_core +from typing_extensions import assert_never from .. import _utils from ..messages import ( @@ -19,6 +20,7 @@ ModelResponseStreamEvent, RetryPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, ) @@ -253,10 +255,15 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]: for word in words: self._usage += _get_string_usage(word) yield self._parts_manager.handle_text_delta(vendor_part_id=i, content=word) - else: + elif isinstance(part, ToolCallPart): yield self._parts_manager.handle_tool_call_part( vendor_part_id=i, tool_name=part.tool_name, args=part.args, tool_call_id=part.tool_call_id ) + elif isinstance(part, ThinkingPart): # pragma: no cover + # NOTE: There's no way to reach this part of the code, since we don't generate ThinkingPart on TestModel. + pass # pragma: no cover + else: + assert_never(part) @property def model_name(self) -> str: diff --git a/pydantic_ai_slim/pyproject.toml b/pydantic_ai_slim/pyproject.toml index e1db8a398..cb8afcb2d 100644 --- a/pydantic_ai_slim/pyproject.toml +++ b/pydantic_ai_slim/pyproject.toml @@ -56,13 +56,13 @@ dependencies = [ # WARNING if you add optional groups, please update docs/install.md logfire = ["logfire>=3.11.0"] # Models -openai = ["openai>=1.75.0"] +openai = ["openai>=1.76.0"] cohere = ["cohere>=5.13.11; platform_system != 'Emscripten'"] vertexai = ["google-auth>=2.36.0", "requests>=2.32.2"] anthropic = ["anthropic>=0.49.0"] -groq = ["groq>=0.15.0"] +groq = ["groq>=0.19.0"] mistral = ["mistralai>=1.2.5"] -bedrock = ["boto3>=1.35.74"] +bedrock = ["boto3>=1.37.24"] # Tools duckduckgo = ["duckduckgo-search>=7.0.0"] tavily = ["tavily-python>=0.5.0"] diff --git a/tests/conftest.py b/tests/conftest.py index e614ea20f..312d13f24 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -24,7 +24,7 @@ from pydantic_ai.messages import BinaryContent from pydantic_ai.models import Model, cached_async_http_client -__all__ = 'IsDatetime', 'IsFloat', 'IsNow', 'IsStr', 'TestEnv', 'ClientWithHandler', 'try_import' +__all__ = 'IsDatetime', 'IsFloat', 'IsInstance', 'IsNow', 'IsStr', 'TestEnv', 'ClientWithHandler', 'try_import' pydantic_ai.models.ALLOW_MODEL_REQUESTS = False @@ -32,12 +32,13 @@ if TYPE_CHECKING: from pydantic_ai.providers.bedrock import BedrockProvider + def IsInstance(*args: Any, **kwargs: Any) -> Any: ... def IsDatetime(*args: Any, **kwargs: Any) -> datetime: ... def IsFloat(*args: Any, **kwargs: Any) -> float: ... def IsNow(*args: Any, **kwargs: Any) -> datetime: ... def IsStr(*args: Any, **kwargs: Any) -> str: ... else: - from dirty_equals import IsDatetime, IsFloat, IsNow as _IsNow, IsStr + from dirty_equals import IsDatetime, IsFloat, IsInstance, IsNow as _IsNow, IsStr def IsNow(*args: Any, **kwargs: Any): # Increase the default value of `delta` to 10 to reduce test flakiness on overburdened machines @@ -245,6 +246,11 @@ def document_content(assets_path: Path) -> BinaryContent: return BinaryContent(data=pdf_bytes, media_type='application/pdf') +@pytest.fixture(scope='session') +def deepseek_api_key() -> str: + return os.getenv('DEEPSEEK_API_KEY', 'mock-api-key') + + @pytest.fixture(scope='session') def openai_api_key() -> str: return os.getenv('OPENAI_API_KEY', 'mock-api-key') diff --git a/tests/models/cassettes/test_anthropic/test_anthropic_model_thinking_part.yaml b/tests/models/cassettes/test_anthropic/test_anthropic_model_thinking_part.yaml new file mode 100644 index 000000000..37e9b4960 --- /dev/null +++ b/tests/models/cassettes/test_anthropic/test_anthropic_model_thinking_part.yaml @@ -0,0 +1,213 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '213' + content-type: + - application/json + host: + - api.anthropic.com + method: POST + parsed_body: + max_tokens: 2048 + messages: + - content: + - text: How do I cross the street? + type: text + role: user + model: claude-3-7-sonnet-latest + stream: false + thinking: + budget_tokens: 1024 + type: enabled + uri: https://api.anthropic.com/v1/messages + response: + headers: + connection: + - keep-alive + content-length: + - '1995' + content-type: + - application/json + transfer-encoding: + - chunked + parsed_body: + content: + - signature: ErUBCkYIAhgCIkD6Sf780fvjL4z6Yhyi47E7OTaBUOozPicKLssA43+GnYsYdzS85o3UQzwQuV+Fu0+H3FEnUKyvBRGa+DDFRIZsEgwmJ7GKgytXI8oSssoaDOQwWyeED8Rn1NGmXSIwoZUSqGbh36VMg5xH0Rp7+9HzCcE1p8r0NFRY/YJ1l9rY6H3tOY55/eBrzfPayiK9Kh0XEK9GAM9LQgQPvaDlvDhdbDFQfcHoClFRoI4r4hgC + thinking: |- + This is a basic question about street safety. I should provide a clear, step-by-step explanation of how to safely cross a street, which is important information for pedestrian safety. + + I'll include: + 1. Finding the right place to cross (crosswalks, intersections) + 2. Checking for traffic signals + 3. Looking both ways for approaching vehicles + 4. Making eye contact with drivers + 5. Walking (not running) across the street + 6. Staying alert while crossing + + I'll keep my answer straightforward but comprehensive enough to cover the safety basics. + type: thinking + - text: "# How to Cross the Street Safely\n\n1. **Find the right place to cross**\n - Use marked crosswalks or intersections + whenever possible\n - Cross at corners where drivers expect pedestrians\n\n2. **Check for traffic signals**\n + \ - Follow pedestrian signals (walk/don't walk) if available\n - At traffic lights, wait for the green light + in your direction\n \n3. **Look both ways before crossing**\n - Look left, right, then left again\n - Continue + watching for traffic as you cross\n \n4. **Make yourself visible**\n - Make eye contact with drivers to ensure + they see you\n - Remove headphones and put away your phone to stay alert\n \n5. **Cross at a steady pace**\n + \ - Walk, don't run, across the street\n - Keep watching for vehicles while crossing\n\nRemember, safety should + always be your priority when crossing streets!" + type: text + id: msg_01SvTnQCjTUgQu19E8qiuHPe + model: claude-3-7-sonnet-20250219 + role: assistant + stop_reason: end_turn + stop_sequence: null + type: message + usage: + cache_creation_input_tokens: 0 + cache_read_input_tokens: 0 + input_tokens: 42 + output_tokens: 332 + status: + code: 200 + message: OK +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '2098' + content-type: + - application/json + host: + - api.anthropic.com + method: POST + parsed_body: + max_tokens: 2048 + messages: + - content: + - text: How do I cross the street? + type: text + role: user + - content: + - signature: ErUBCkYIAhgCIkD6Sf780fvjL4z6Yhyi47E7OTaBUOozPicKLssA43+GnYsYdzS85o3UQzwQuV+Fu0+H3FEnUKyvBRGa+DDFRIZsEgwmJ7GKgytXI8oSssoaDOQwWyeED8Rn1NGmXSIwoZUSqGbh36VMg5xH0Rp7+9HzCcE1p8r0NFRY/YJ1l9rY6H3tOY55/eBrzfPayiK9Kh0XEK9GAM9LQgQPvaDlvDhdbDFQfcHoClFRoI4r4hgC + thinking: |- + This is a basic question about street safety. I should provide a clear, step-by-step explanation of how to safely cross a street, which is important information for pedestrian safety. + + I'll include: + 1. Finding the right place to cross (crosswalks, intersections) + 2. Checking for traffic signals + 3. Looking both ways for approaching vehicles + 4. Making eye contact with drivers + 5. Walking (not running) across the street + 6. Staying alert while crossing + + I'll keep my answer straightforward but comprehensive enough to cover the safety basics. + type: thinking + - text: "# How to Cross the Street Safely\n\n1. **Find the right place to cross**\n - Use marked crosswalks or intersections + whenever possible\n - Cross at corners where drivers expect pedestrians\n\n2. **Check for traffic signals**\n + \ - Follow pedestrian signals (walk/don't walk) if available\n - At traffic lights, wait for the green light + in your direction\n \n3. **Look both ways before crossing**\n - Look left, right, then left again\n - Continue + watching for traffic as you cross\n \n4. **Make yourself visible**\n - Make eye contact with drivers to ensure + they see you\n - Remove headphones and put away your phone to stay alert\n \n5. **Cross at a steady pace**\n + \ - Walk, don't run, across the street\n - Keep watching for vehicles while crossing\n\nRemember, safety should + always be your priority when crossing streets!" + type: text + role: assistant + - content: + - text: Considering the way to cross the street, analogously, how do I cross the river? + type: text + role: user + model: claude-3-7-sonnet-latest + stream: false + thinking: + budget_tokens: 1024 + type: enabled + uri: https://api.anthropic.com/v1/messages + response: + headers: + connection: + - keep-alive + content-length: + - '2684' + content-type: + - application/json + transfer-encoding: + - chunked + parsed_body: + content: + - signature: ErUBCkYIAhgCIkB2BUY56TQbBYl46yDgVWTsaHGOGtJS3iTMiAnLZZUSqxqwSlIDAu7VINAVKPkt1rPdRmQbD/pnQXmHUWPtg3JMEgwX5++FVgV41/x9mtwaDJHFKMSNqLpHIsc3jSIwus0KQjezK3yrtzqekYfYulN1ZGKj9Jo5JmVIjLpvM4eXKq9E3K1YP7fWB/radhmbKh3pq4qSkEvr+QrxqVUlJoAdTB4LFRD6aWbtXGyzKhgC + thinking: |- + This question is asking me to apply similar principles for crossing a street to crossing a river, using analogy. Let me think about the comparable safety concerns and steps: + + Street crossing safety elements: + 1. Finding the right place to cross (crosswalks, intersections) + 2. Checking for signals/traffic + 3. Looking both ways + 4. Being visible + 5. Crossing at a steady pace + 6. Staying alert + + For river crossing, I'll need to address: + 1. Finding the right place to cross (bridges, shallow areas, designated crossing points) + 2. Checking conditions (current, depth) + 3. Looking for hazards + 4. Safety equipment/visibility + 5. Crossing method and pace + 6. Staying alert for changing conditions + + I'll structure my answer similarly to the street crossing response, focusing on safety while acknowledging the different hazards and methods relevant to river crossing. + type: thinking + - text: |- + # How to Cross a River Safely + + 1. **Find the right place to cross** + - Use bridges or designated crossing points whenever possible + - Look for shallow areas with slow-moving water if no bridge is available + - Avoid areas with strong currents, rapids, or debris + + 2. **Check the river conditions** + - Assess water depth, speed, and clarity before attempting to cross + - Check for underwater hazards like slippery rocks or drop-offs + - Consider recent weather (rain can create dangerous conditions) + + 3. **Look upstream and downstream** + - Scan for approaching hazards like floating debris or boats + - Identify a safe exit point on the opposite bank + + 4. **Prepare properly** + - Wear appropriate footwear with good grip + - Consider using a walking stick for balance and depth testing + - Secure belongings in waterproof containers + + 5. **Cross with caution** + - Face upstream and move diagonally across with the current + - Maintain three points of contact when possible + - Move steadily but don't rush + + Remember, unlike streets, rivers are natural environments with changing conditions. If the crossing looks risky, it's best to find another route or seek assistance! + type: text + id: msg_01W2NZXnzuNgCkVbvyBywWKb + model: claude-3-7-sonnet-20250219 + role: assistant + stop_reason: end_turn + stop_sequence: null + type: message + usage: + cache_creation_input_tokens: 0 + cache_read_input_tokens: 0 + input_tokens: 266 + output_tokens: 479 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_anthropic/test_anthropic_model_thinking_part_stream.yaml b/tests/models/cassettes/test_anthropic/test_anthropic_model_thinking_part_stream.yaml new file mode 100644 index 000000000..928492948 --- /dev/null +++ b/tests/models/cassettes/test_anthropic/test_anthropic_model_thinking_part_stream.yaml @@ -0,0 +1,232 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '212' + content-type: + - application/json + host: + - api.anthropic.com + method: POST + parsed_body: + max_tokens: 2048 + messages: + - content: + - text: How do I cross the street? + type: text + role: user + model: claude-3-7-sonnet-latest + stream: true + thinking: + budget_tokens: 1024 + type: enabled + uri: https://api.anthropic.com/v1/messages + response: + body: + string: |+ + event: message_start + data: {"type":"message_start","message":{"id":"msg_01EMVWy3UmSrXx8QDqDVJu3J","type":"message","role":"assistant","model":"claude-3-7-sonnet-20250219","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":42,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":2}} } + + event: content_block_start + data: {"type":"content_block_start","index":0,"content_block":{"type":"thinking","thinking":"","signature":""} } + + event: ping + data: {"type": "ping"} + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"This"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" is a straightforward question about"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" pedestrian safety. I should provide clear, practical"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" advice on how to safely cross a"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" street, which is an everyday"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" activity that everyone should know how to"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" do properly.\n\nI'll include"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" the basic steps:\n1. Fin"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"d an appropriate place to cross (cross"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"walk, intersection)\n2. Stop at"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" the edge of the street\n3. Look"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" both ways (left-right-left in"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" countries with right-side driving;"}} + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" right-left-right in left"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"-side driving countries)\n4. Listen"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" for oncoming traffic\n5."} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" Cross when clear, or when"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" pedestrian signals indicate it's safe"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"\n6. Stay alert while crossing\n7. Walk"}} + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":", don't run\n\nI'll keep"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":" my answer concise and clear"}} + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":", as this is a straight"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"thinking_delta","thinking":"forward safety question."} } + + event: content_block_delta + data: {"type":"content_block_delta","index":0,"delta":{"type":"signature_delta","signature":"ErUBCkYIAhgCIkBae3G0d++H4kiUhcpgulrNH2UtKjeUX71wQ7N236PJ7eiWX0qBJjRPoCjmIXcax+Vikx6EQIabVzpoRW3IPrgiEgy2bMcGLce7+wzJBBoaDOE//A8Scwe+4aexWiIw5O8E22fvilfUPxe4t3HJl/+6zKSePdDr2SI5DAzjH8tecOlVH8TQ9axJ4yZg9+sGKh2s08YMFuwuRmro7qe9xH39ZjwnVb/c493it57aiBgC"} } + + event: content_block_stop + data: {"type":"content_block_stop","index":0 } + + event: content_block_start + data: {"type":"content_block_start","index":1,"content_block":{"type":"text","text":""} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"# How to Cross the Street Safely\n\n1. **"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"Find the right spot to cross**"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"\n - Use a crosswalk,"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" pedestrian crossing, or intersection"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" when available\n -"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" Avoid crossing between parked cars or on"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" blind curves\n\n2. **"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"Stop at the curb or"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" edge of the road**"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"\n\n3. **Look both ways carefully"}} + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"**\n - Look left, then"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" right, then left again ("} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"in right-driving countries)\n -"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" Look right, then left,"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" then right again (in left-driving countries)"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"\n\n4. **Wait for traffic"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" to clear or signals to change**\n "} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"- At traffic lights, cross only"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" when you have the \"walk\" signal\n "} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"- Make eye contact with drivers to"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" ensure they see you\n\n5"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":". **Cross at a steady pace**"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" - walk, don't run"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"\n \n6. **Stay alert"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"** - continue looking for traffic"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" as you cross\n\n7."} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" **Use extra caution in"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" poor weather or low visibility"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":"**\n\nRemember that local traffic laws may vary"} } + + event: content_block_delta + data: {"type":"content_block_delta","index":1,"delta":{"type":"text_delta","text":" depending on your location."}} + + event: content_block_stop + data: {"type":"content_block_stop","index":1 } + + event: message_delta + data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":394}} + + event: message_stop + data: {"type":"message_stop" } + + headers: + cache-control: + - no-cache + connection: + - keep-alive + content-type: + - text/event-stream; charset=utf-8 + transfer-encoding: + - chunked + status: + code: 200 + message: OK +version: 1 +... diff --git a/tests/models/cassettes/test_bedrock/test_bedrock_model_thinking_part.yaml b/tests/models/cassettes/test_bedrock/test_bedrock_model_thinking_part.yaml new file mode 100644 index 000000000..243b1a8fd --- /dev/null +++ b/tests/models/cassettes/test_bedrock/test_bedrock_model_thinking_part.yaml @@ -0,0 +1,206 @@ +interactions: +- request: + body: '{"messages": [{"role": "user", "content": [{"text": "How do I cross the street?"}]}], "system": [], "inferenceConfig": + {}}' + headers: + amz-sdk-invocation-id: + - !!binary | + NWMyN2FhM2ItOTBmOC00NDc2LTkxNWUtYjg1NmFjODE4MTY4 + amz-sdk-request: + - !!binary | + YXR0ZW1wdD0x + content-length: + - '122' + content-type: + - !!binary | + YXBwbGljYXRpb24vanNvbg== + method: POST + uri: https://bedrock-runtime.us-east-1.amazonaws.com/model/us.deepseek.r1-v1%3A0/converse + response: + headers: + connection: + - keep-alive + content-length: + - '4296' + content-type: + - application/json + parsed_body: + metrics: + latencyMs: 24594 + output: + message: + content: + - text: "\n\nCrossing the street safely involves following key steps to ensure your safety. Here's a clear guide:\n\n### + **Steps to Cross Safely:**\n1. **Find a Safe Spot** \n - Use a **marked crosswalk** or pedestrian crossing + whenever possible. If unavailable, choose an intersection where drivers expect pedestrians.\n - Avoid crossing + between parked cars or mid-block, as drivers may not see you.\n\n2. **Check for Traffic Signals** \n - If + there's a traffic light or walk signal, wait for the \"walk\" symbol (or green light where pedestrian signals + aren't present). \n - **Don't start crossing on a flashing \"don't walk\"** or red light—finish crossing + if you've already started.\n\n3. **Look Both Ways** \n - **Left-Right-Left**: Look left, right, and left + again before stepping into the street. In countries with right-side driving, check for cars turning left. In + left-side driving countries (e.g., UK, Japan), check right first. \n - **Make eye contact** with drivers + to ensure they see you, even if you have the right of way.\n\n4. **Stay Alert While Crossing** \n - Keep + looking for traffic as you cross. Watch for turning vehicles, bikes, or scooters. \n - Walk at a steady pace—don't + run, but avoid lingering.\n\n5. **Use Medians if Available** \n - If the street has a median (center island), + treat it as a halfway point. Stop there and check traffic again before continuing.\n\n### **Additional Safety + Tips:**\n- **Avoid Distractions**: Put away phones, remove headphones, and stay focused. \n- **Visibility**: + At night, wear reflective clothing or carry a light. \n- **Children/Disabilities**: Hold children's hands. + Those with mobility aids should use designated crossings where possible. \n- **Right of Way**: Never assume + a driver will stop—wait for vehicles to halt before stepping into the road.\n\n### **Special Situations:**\n- + **Uncontrolled Crossings (no signals)**: Wait for a large gap in traffic. Cross perpendicular to the road (straight + line). \n- **Roundabouts**: Use crosswalks before entering the circle, and watch for multiple lanes of traffic. + \ \n- **Highways/Freeways**: Avoid crossing—seek an overpass or underpass instead.\n\nBy staying vigilant and + following these steps, you can cross the street safely! \U0001F6B8" + - reasoningContent: + reasoningText: + text: "Okay, the user is asking how to cross the street. Let me think about the best way to explain this. + First, I need to make sure they understand the basic steps but also stay safe. Maybe start by finding a + safe place to cross. Like a crosswalk or pedestrian crossing. If there's a traffic light, they should wait + for the walk signal. But if there's no signal, they need to look both ways. Wait until there's no traffic + coming, right?\n\nWait, what if there's a crosswalk but no lights? They should still check for cars. Maybe + mention making eye contact with drivers to ensure they're seen. Also, don't forget to keep looking while + crossing, in case a car appears suddenly. What about intersections without marked crosswalks? They should + still cross there rather than mid-block because drivers expect pedestrians at intersections. \n\nOh, and + distractions like phones or headphones. They should avoid those to stay alert. Teach them to walk, not run, + but keep a steady pace. If there's a median, maybe use it as a halfway point. Also, in some countries, traffic + drives on the left, so check the correct direction when looking. \n\nWhat about children or people with + disabilities? Maybe add something about holding hands with kids or using assistive devices. And if it's + dark, wearing reflective clothing could help. Are there any other safety tips? Maybe don't assume drivers + will stop, even if you have the right of way. Always double-check. \n\nLet me structure this step by step. + Start with finding a safe spot, check signals, look both ways, stay visible, keep monitoring traffic, and + avoid distractions. Maybe number the steps for clarity. Also, include additional tips for different scenarios. + Okay, that should cover the essentials without being too complicated.\n" + role: assistant + stopReason: end_turn + usage: + inputTokens: 12 + outputTokens: 882 + totalTokens: 894 + status: + code: 200 + message: OK +- request: + body: '{"messages": [{"role": "user", "content": [{"text": "How do I cross the street?"}]}, {"role": "assistant", "content": + [{"text": "\n\nCrossing the street safely involves following key steps to ensure your safety. Here''s a clear guide:\n\n### + **Steps to Cross Safely:**\n1. **Find a Safe Spot** \n - Use a **marked crosswalk** or pedestrian crossing whenever + possible. If unavailable, choose an intersection where drivers expect pedestrians.\n - Avoid crossing between parked + cars or mid-block, as drivers may not see you.\n\n2. **Check for Traffic Signals** \n - If there\u2019s a traffic + light or walk signal, wait for the \"walk\" symbol (or green light where pedestrian signals aren\u2019t present). \n - + **Don\u2019t start crossing on a flashing \"don\u2019t walk\"** or red light\u2014finish crossing if you\u2019ve already + started.\n\n3. **Look Both Ways** \n - **Left-Right-Left**: Look left, right, and left again before stepping into + the street. In countries with right-side driving, check for cars turning left. In left-side driving countries (e.g., + UK, Japan), check right first. \n - **Make eye contact** with drivers to ensure they see you, even if you have the + right of way.\n\n4. **Stay Alert While Crossing** \n - Keep looking for traffic as you cross. Watch for turning vehicles, + bikes, or scooters. \n - Walk at a steady pace\u2014don\u2019t run, but avoid lingering.\n\n5. **Use Medians if Available** \n - + If the street has a median (center island), treat it as a halfway point. Stop there and check traffic again before continuing.\n\n### + **Additional Safety Tips:**\n- **Avoid Distractions**: Put away phones, remove headphones, and stay focused. \n- **Visibility**: + At night, wear reflective clothing or carry a light. \n- **Children/Disabilities**: Hold children\u2019s hands. Those + with mobility aids should use designated crossings where possible. \n- **Right of Way**: Never assume a driver will + stop\u2014wait for vehicles to halt before stepping into the road.\n\n### **Special Situations:**\n- **Uncontrolled + Crossings (no signals)**: Wait for a large gap in traffic. Cross perpendicular to the road (straight line). \n- **Roundabouts**: + Use crosswalks before entering the circle, and watch for multiple lanes of traffic. \n- **Highways/Freeways**: Avoid + crossing\u2014seek an overpass or underpass instead.\n\nBy staying vigilant and following these steps, you can cross + the street safely! \ud83d\udeb8"}]}, {"role": "user", "content": [{"text": "Considering the way to cross the street, + analogously, how do I cross the river?"}]}], "system": [], "inferenceConfig": {}, "additionalModelRequestFields": {"thinking": + {"type": "enabled", "budget_tokens": 1024}}}' + headers: + amz-sdk-invocation-id: + - !!binary | + ODFkYmUyODUtN2EzMy00NjE2LTk3NWQtMDU3YjI5MjA0ZmNh + amz-sdk-request: + - !!binary | + YXR0ZW1wdD0x + content-length: + - '2720' + content-type: + - !!binary | + YXBwbGljYXRpb24vanNvbg== + method: POST + uri: https://bedrock-runtime.us-east-1.amazonaws.com/model/us.anthropic.claude-3-7-sonnet-20250219-v1%3A0/converse + response: + headers: + connection: + - keep-alive + content-length: + - '3598' + content-type: + - application/json + parsed_body: + metrics: + latencyMs: 16324 + output: + message: + content: + - reasoningContent: + reasoningText: + signature: ErcBCkgIAhABGAIiQMuiyDObz/Z/ryneAVaQDk4iH6JqSNKJmJTwpQ1RqPz07UFTEffhkJW76u0WVKZaYykZAHmZl/IbQOPDLGU0nhQSDDuHLg82YIApYmWyfhoMe8vxT1/WGTJwyCeOIjC5OfF0+c6JOAvXvv9ElFXHo3yS3am1V0KpTiFj4YCy/bqfxv1wFGBw0KOMsTgq7ugqHeuOpzNM91a/RgtYHUdrcAKm9iCRu24jIOCjr5+h + text: |- + This is an interesting analogy! The person is asking me to use the street-crossing principles I just outlined and apply them to crossing a river. I'll create an analogous guide for river crossing, keeping the same safety-focused structure but adapting it to the water environment. + + I should include: + 1. Finding safe crossing spots (like bridges, ferries, or shallow fords) + 2. Checking conditions (water level, current speed, weather) + 3. Looking for hazards (similar to looking both ways) + 4. Crossing techniques + 5. Staying alert during crossing + 6. Special situations + + I'll make sure to emphasize safety throughout, just as I did with street crossing. + - text: |- + # How to Cross a River Safely + + Just as with street crossing, river crossing requires careful assessment and proper technique. Here's how to approach it safely: + + ### **Steps to Cross a River:** + + 1. **Find a Safe Crossing Point** + - Use **established bridges** or **ferry services** whenever possible + - If you must ford the river, look for wide, shallow sections with slower current + - Avoid narrow, deep sections where water moves quickly + + 2. **Assess River Conditions** + - **Check water levels and flow rate** before attempting to cross + - Look for debris or floating hazards (like logs) coming downstream + - Consider recent weather—rain upstream can cause sudden changes in water level + + 3. **Evaluate Before Entering** + - **Upstream-Downstream-Upstream**: Look for hazards upstream that might flow toward you, downstream for where you might drift if swept away, then upstream again + - **Test depth** with a walking stick before committing to cross + + 4. **Cross Safely** + - Face **upstream at an angle** (diagonal crossing) to avoid being knocked over + - Use a **walking stick or trekking pole** for a third point of contact + - Unbuckle backpack waist straps so you can shed gear quickly if you fall + + 5. **Stay Alert While Crossing** + - Move deliberately with careful foot placement + - Continue monitoring upstream for approaching hazards + - Maintain at least two points of contact with the riverbed at all times + + ### **Additional Safety Tips:** + - **Depth Check**: Water above knee-height becomes significantly more dangerous + - **Footwear**: Keep shoes on to protect feet from rocks and debris + - **Group Crossing**: Link arms in a line facing upstream for stability in moderate currents + - **Emergency Plan**: Know what to do if swept away (float on back, feet downstream) + + ### **Special Situations:** + - **Deep Rivers**: Seek proper water craft rather than swimming across + - **Winter Crossings**: Be extremely cautious with ice—thickness may vary + - **Flash Flood Areas**: If water is rising or muddy/turbulent, wait it out instead of crossing + - **Wildlife Concerns**: Check for crocodiles, hippos, or other dangerous animals in relevant regions + + Remember: When in doubt, don't cross! Unlike streets, rivers can change conditions rapidly and unpredictably. + role: assistant + stopReason: end_turn + usage: + cacheReadInputTokenCount: 0 + cacheReadInputTokens: 0 + cacheWriteInputTokenCount: 0 + cacheWriteInputTokens: 0 + inputTokens: 636 + outputTokens: 690 + totalTokens: 1326 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_bedrock/test_bedrock_model_thinking_part_stream.yaml b/tests/models/cassettes/test_bedrock/test_bedrock_model_thinking_part_stream.yaml new file mode 100644 index 000000000..47e913b75 --- /dev/null +++ b/tests/models/cassettes/test_bedrock/test_bedrock_model_thinking_part_stream.yaml @@ -0,0 +1,2053 @@ +interactions: +- request: + body: '{"messages": [{"role": "user", "content": [{"text": "How do I cross the street?"}]}], "system": [], "inferenceConfig": + {}}' + headers: + amz-sdk-invocation-id: + - !!binary | + MzRkY2NkNWYtNDQ3YS00OGVhLThjZTgtZTBjM2E2OWY3ZDdj + amz-sdk-request: + - !!binary | + YXR0ZW1wdD0x + content-length: + - '122' + content-type: + - !!binary | + YXBwbGljYXRpb24vanNvbg== + method: POST + uri: https://bedrock-runtime.us-east-1.amazonaws.com/model/us.deepseek.r1-v1%3A0/converse-stream + response: + body: + string: !!binary | + AAAAiAAAAFJh0RTiCzpldmVudC10eXBlBwAMbWVzc2FnZVN0YXJ0DTpjb250ZW50LXR5cGUHABBh + cHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsicCI6ImFiY2RlZmdoaWprIiwi + cm9sZSI6ImFzc2lzdGFudCJ9t/VqyQAAANYAAABXlpiRxws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQi + OnsidGV4dCI6Ik9rYXkifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdI + SUoifb7Si98AAADsAAAAV30JMeALOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29u + dGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRl + bnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIsIHNv + In19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVW + V1hZWjAxMjM0NSJ9jQqdtQAAAMIAAABXA/ighQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0Rl + bHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVu + dHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4 + dCI6IiB0aGUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wIn0lybAuAAAA0AAAAFcZ2GRnCzpldmVu + dC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pz + b24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsi + cmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHVzZXIgaXMifX0sInAiOiJhYmNkZWZnaGlqa2xt + bm9wcXJzdHV2d3h5eiJ9NJ5RiAAAAPkAAABX1QkpEgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9j + a0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVl + dmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsi + dGV4dCI6IiBhc2tpbmcgaG93IHRvIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpB + QkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3OCJ9iscBxQAAANoAAABXU2h8xgs6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7 + InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBjcm9zcyB0aGUgc3RyZWV0In19LCJwIjoiYWJj + ZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBIn3CZHHdAAAA0AAAAFcZ2GRnCzpldmVudC10eXBlBwAR + Y29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3Nh + Z2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5n + Q29udGVudCI6eyJ0ZXh0IjoiLiBMZXQgbWUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 + d3h5eiJ9PF/W4QAAAL0AAABXeHrXmws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpj + b250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29u + dGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiB0 + aGluayJ9fSwicCI6ImFiY2RlZmdoaSJ9uayrTwAAAO8AAABXOqlLMAs6ZXZlbnQtdHlwZQcAEWNv + bnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdl + LXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0Nv + bnRlbnQiOnsidGV4dCI6IiBhYm91dCBob3cifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 + d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyIn1qNN/XAAAAvQAAAFd4etebCzpldmVu + dC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pz + b24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsi + cmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHRvIGFwcHJvYWNoIn19LCJwIjoiYWJjIn03zXZC + AAAAwgAAAFcD+KCFCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlw + ZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJ + bmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHRoaXMuIEZpcnN0 + In19LCJwIjoiYWJjZGVmZ2gifdK6XBcAAADXAAAAV6v4uHcLOmV2ZW50LXR5cGUHABFjb250ZW50 + QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBl + BwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50 + Ijp7InRleHQiOiIsIEkgbmVlZCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJD + REVGRyJ9uGXA2wAAAOgAAABXiImXIAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpj + b250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29u + dGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiB0 + byBtYWtlIHN1cmUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpL + TE1OT1BRUlMiffpdrvkAAADQAAAAVxnYZGcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0 + YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7 + ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQi + OiIgSSBjb3ZlciJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6In1yJupYAAAA2wAA + AFduCFV2CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFw + cGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6 + MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGFsbCB0aGUgYmFzaWMifX0s + InAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFIn1XGl8aAAAAxgAAAFf2eAZFCzpl + dmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9u + L2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEi + OnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHN0ZXBzLCJ9fSwicCI6ImFiY2RlZmdoaWpr + bG1ub3BxIn1Inw9PAAAAvwAAAFcCuoT7CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGEN + OmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJj + b250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0Ijoi + IGJ1dCBhbHNvIn19LCJwIjoiYWJjZGVmZ2gifTkF6KUAAADVAAAAV9E46xcLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25p + bmdDb250ZW50Ijp7InRleHQiOiIgY29uc2lkZXIgZGlmZmVyZW50In19LCJwIjoiYWJjZGVmZ2hp + amtsbW5vcHFyc3QifQYIT2kAAAD0AAAAVy2Z7aMLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tE + ZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZl + bnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRl + eHQiOiIgc2NlbmFyaW9zLiBNYXliZSJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6 + QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowIn0en7cxAAAAywAAAFcO6ML0CzpldmVudC10eXBl + BwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1l + c3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29u + aW5nQ29udGVudCI6eyJ0ZXh0IjoiIHN0YXJ0IHdpdGggdGhlIn19LCJwIjoiYWJjZGVmZ2hpamts + bW4ifdnWiaMAAADTAAAAV154HrcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29u + dGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRl + bnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgb2J2 + aW91czoifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCIn1aVMHZAAAAygAAAFcz + iOtECzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxp + Y2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwi + ZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGZpbmRpbmcifX0sInAiOiJhYmNk + ZWZnaGlqa2xtbm9wcXJzdCJ9htsdEwAAAN8AAABXm4jztgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQi + OnsidGV4dCI6IiBhIGNyb3NzIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE + RUZHSElKS0xNTk8ifdRb0/wAAAC5AAAAV436cVsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tE + ZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZl + bnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRl + eHQiOiJ3YWxrLiJ9fSwicCI6ImFiY2RlZiJ9dwn7ewAAAMMAAABXPpiJNQs6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmlu + Z0NvbnRlbnQiOnsidGV4dCI6IiBCdXQgd2FpdCwifX0sInAiOiJhYmNkZWZnaGlqayJ97sPHFgAA + AOcAAABXCtkA8Qs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUH + ABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5k + ZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBub3QgYWxsIn19LCJw + IjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWVyJ9k0Zf + uAAAANUAAABX0TjrFws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5 + cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2Nr + SW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBzdHJlZXRzIn19 + LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERSJ9UBY5AgAAAPIAAABXotkYAws6 + ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv + bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRh + Ijp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBoYXZlIGNyb3NzIn19LCJwIjoiYWJjZGVm + Z2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0In2/QJeR + AAAA3QAAAFfhSKDWCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlw + ZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJ + bmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0Ijoid2Fsa3MsIn19LCJw + IjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk8ifTzTHw4AAADoAAAA + V4iJlyALOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBw + bGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4Ijow + LCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgZXNwZWNpYWxseSBpbiBsZXNz + In19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNIn0NwBC9AAAA + 8wAAAFefuTGzCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcA + EGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRl + eCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHVyYmFuIGFyZWFzLiJ9 + fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldY + WVowMTIzIn2nbYZtAAAAywAAAFcO6ML0CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGEN + OmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJj + b250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0Ijoi + IFNvIEkgc2hvdWxkIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHEifREMNq4AAADBAAAAV0RY2lUL + OmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRp + b24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0 + YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgbWVudGlvbiBsb29raW5nIn19LCJwIjoi + YWJjIn2ZsijvAAAAzQAAAFeBqDdUCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNv + bnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250 + ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGZv + ciJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QSJ96T6tEAAAAOgAAABXiImXIAs6 + ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv + bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRh + Ijp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBhIGNyb3Nzd2FsayJ9fSwicCI6ImFiY2Rl + ZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1QifRVlAksAAADiAAAAV8I5 + j4ELOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGlj + YXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJk + ZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgb3IifX0sInAiOiJhYmNkZWZnaGlq + a2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXIn1hbza/AAAA4QAAAFeFmfVR + CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0 + aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVs + dGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHBlZGVzdHJpYW4gY3Jvc3NpbmcifX0s + InAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFIn3W5NyfAAAAxQAAAFex2HyVCzpl + dmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9u + L2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEi + OnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHNpZ25hbHMifX0sInAiOiJhYmNkZWZnaGlq + a2xtbm8iffqqiF4AAADtAAAAV0BpGFALOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06 + Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNv + bnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIg + Zmlyc3QuXG5cbiJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktM + TU5PUFFSU1RVVldYWVoifb/r1l4AAADkAAAAV015eiELOmV2ZW50LXR5cGUHABFjb250ZW50Qmxv + Y2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAF + ZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7 + InRleHQiOiJUaGVuLCBjaGVjayJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJD + REVGR0hJSktMTU5PUFEifZTpzS8AAADdAAAAV+FIoNYLOmV2ZW50LXR5cGUHABFjb250ZW50Qmxv + Y2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAF + ZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7 + InRleHQiOiIgZm9yIHRyYWZmaWMgbGlnaHRzIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1 + dnd4eXpBQiJ9reOjpAAAAOQAAABXTXl6IQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6 + Ii4gSWYifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BR + UlNUVVZXWCJ9jQ3CxQAAAL4AAABXP9qtSws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6 + IiB0aGVyZSdzIn19LCJwIjoiYWJjZGVmZ2gifZjb/rsAAADoAAAAV4iJlyALOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25p + bmdDb250ZW50Ijp7InRleHQiOiIgYSB0cmFmZmljIGxpZ2h0In19LCJwIjoiYWJjZGVmZ2hpamts + bW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QIn2TTVkcAAAAvQAAAFd4etebCzpldmVudC10 + eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N + Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVh + c29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiLCB3YWl0In19LCJwIjoiYWJjZGVmZ2hpIn0geXIRAAAA + 3wAAAFebiPO2CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcA + EGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRl + eCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGZvciB0aGUifX0sInAi + OiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OTyJ90yPCxQAAAOkAAABX + tem+kAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBs + aWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAs + ImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiB3YWxrIn19LCJwIjoiYWJjZGVm + Z2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxIn2M2R2NAAAA + 1gAAAFeWmJHHCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcA + EGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRl + eCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHNpZ25hbC4gQnV0In19 + LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQiJ9kKn5TQAAANUAAABX0TjrFws6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7 + InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBzb21ldGltZXMifX0sInAiOiJhYmNkZWZnaGlq + a2xtbm9wcXJzdHV2d3h5ekFCQyJ9Wi2WNgAAAPQAAABXLZntows6ZXZlbnQtdHlwZQcAEWNvbnRl + bnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5 + cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRl + bnQiOnsidGV4dCI6IiBwZW9wbGUgbWlnaHQgbm90In19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFy + c3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAifdzAJ8kAAADAAAAAV3k48+ULOmV2 + ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24v + anNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6 + eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIga25vdyB3aGF0In19LCJwIjoiYWJjZGVmZ2gi + fap4CEYAAADDAAAAVz6YiTULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVu + dC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRC + bG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgdGhlIHN5 + bWJvbHMifX0sInAiOiJhYmNkZWZnaGkifXv8WCMAAADiAAAAV8I5j4ELOmV2ZW50LXR5cGUHABFj + b250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2Fn + ZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdD + b250ZW50Ijp7InRleHQiOiIgbWVhbi4gTWF5YmUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJz + dHV2d3h5ekFCQ0RFRkdISUpLTE1OIn3j/DgJAAAAywAAAFcO6ML0CzpldmVudC10eXBlBwARY29u + dGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2Ut + dHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29u + dGVudCI6eyJ0ZXh0IjoiIGV4cGxhaW4gdGhlIFwiIn19LCJwIjoiYWJjZGVmZ2hpamtsbW4ifcxB + PCIAAADdAAAAV+FIoNYLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10 + eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9j + a0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiJ3YWxrXCIifX0s + InAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OTyJ9nLYRMQAAAL0A + AABXeHrXmws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBh + cHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgi + OjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBhbmQgXCJkb24ifX0sInAi + OiJhYmNkZSJ9zz1UJAAAAN0AAABX4Uig1gs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6 + Iid0IHdhbGtcIiJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktM + In39jowtAAAA7wAAAFc6qUswCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRl + bnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50 + QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHNpZ25h + bHMuIEFsc28ifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1O + T1BRUlNUVVZXWFkifSIW1e8AAADRAAAAVyS4TdcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tE + ZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZl + bnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRl + eHQiOiIsIGluIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERSJ9pIre1QAA + ANAAAABXGdhkZws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUH + ABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5k + ZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBzb21lIHBsYWNlcyJ9 + fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXYifUbFeDYAAADlAAAAV3AZU5ELOmV2ZW50LXR5 + cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06 + bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFz + b25pbmdDb250ZW50Ijp7InRleHQiOiIsIHRoZXJlIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFy + c3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWIn2EyM/zAAAA1gAAAFeWmJHHCzpldmVudC10 + eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N + Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVh + c29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGFyZSBjb3VudCJ9fSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3eHl6QUJDRCJ9erYhXwAAAPIAAABXotkYAws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQi + OnsidGV4dCI6ImRvd24gdGltIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE + RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3In2uDUosAAAAygAAAFcziOtECzpldmVudC10 + eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N + Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVh + c29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiZXJzIHdoaWNoIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5v + cHFycyJ9Ej245AAAAPEAAABX5Xli0ws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpj + b250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29u + dGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBj + YW4gaGVscC4ifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1O + T1BRUlNUVVZXWFlaMDEyMzQifcE13Y0AAADUAAAAV+xYwqcLOmV2ZW50LXR5cGUHABFjb250ZW50 + QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBl + BwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50 + Ijp7InRleHQiOiIgQnV0IHdoYXQifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFC + QyJ9Ld6O9gAAAOMAAABX/1mmMQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250 + ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVu + dEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBpZiB0 + aGVyZSdzIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9Q + In3keZ63AAAA0QAAAFckuE3XCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRl + bnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50 + QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIG5vIHRy + YWZmaWMifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3gifTTncDUAAADwAAAAV9gZS2ML + OmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRp + b24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0 + YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgbGlnaHQ/In19LCJwIjoiYWJjZGVmZ2hp + amtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTYifQg36UYA + AADSAAAAV2MYNwcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgVGhlbiB0aGV5IHNo + b3VsZCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnMifbygY9oAAADaAAAAV1NofMYLOmV2ZW50 + LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNv + bg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJy + ZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgbG9vayBib3RoIHdheXMifX0sInAiOiJhYmNkZWZn + aGlqa2xtbm9wcXJzdHV2d3h5ekFCQyJ9Y69EqQAAANsAAABXbghVdgs6ZXZlbnQtdHlwZQcAEWNv + bnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdl + LXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0Nv + bnRlbnQiOnsidGV4dCI6IiBmb3IgY2Fycy4ifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 + d3h5ekFCQ0RFRkdISSJ9BqSvFwAAAMMAAABXPpiJNQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9j + a0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVl + dmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsi + dGV4dCI6IiBCdXQgaG93In19LCJwIjoiYWJjZGVmZ2hpamtsbSJ9S33y9gAAAOsAAABXzynt8As6 + ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv + bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRh + Ijp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBtYW55In19LCJwIjoiYWJjZGVmZ2hpamts + bW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjMifaaSSlwAAADrAAAA + V88p7fALOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBw + bGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4Ijow + LCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgdGltZXM/In19LCJwIjoiYWJj + ZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxIn2RIOBR + AAAA4wAAAFf/WaYxCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlw + ZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJ + bmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIFVzdWFsbHkifX0s + InAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlMifdCZOTYA + AAC4AAAAV7CaWOsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgbGVmdCJ9fSwicCI6 + ImFiY2RlIn1UykKhAAAA8QAAAFfleWLTCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGEN + OmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJj + b250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0Ijoi + LXJpZ2h0In19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9Q + UVJTVFVWV1hZWjAxMjM0NTY3OCJ9/aupqgAAALgAAABXsJpY6ws6ZXZlbnQtdHlwZQcAEWNvbnRl + bnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5 + cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRl + bnQiOnsidGV4dCI6Ii1sZWZ0LCJ9fSwicCI6ImFiY2QifUzSvg8AAADnAAAAVwrZAPELOmV2ZW50 + LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNv + bg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJy + ZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgYnV0IG1heWJlIGNsYXJpZnkifX0sInAiOiJhYmNk + ZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE0ifQT6oCkAAADjAAAAV/9ZpjELOmV2 + ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24v + anNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6 + eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgdGhhdC5cblxuIn19LCJwIjoiYWJjZGVmZ2hp + amtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUSJ9MuNgWgAAAPIAAABXotkYAws6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7 + InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IldhaXQsIGJ1dCJ9fSwicCI6ImFiY2RlZmdoaWpr + bG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU2In38Ibw1AAAA + 0wAAAFdeeB63CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcA + EGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRl + eCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGluIn19LCJwIjoiYWJj + ZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSCJ9r9TonQAAAOoAAABX8knEQAs6ZXZlbnQt + dHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29u + DTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJl + YXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBzb21lIGNvdW50cmllcywifX0sInAiOiJhYmNkZWZn + aGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUiJ958dPbAAAAMQAAABXjLhVJQs6 + ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv + bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRh + Ijp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiB0cmFmZmljIGNvbWVzIn19LCJwIjoiYWJj + ZGVmZ2gifUivKjIAAADGAAAAV/Z4BkULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06 + Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNv + bnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIg + ZnJvbSB0aGUgb3Bwb3NpdGUifX0sInAiOiJhYmNkZWYifWfKP9IAAAD1AAAAVxD5xBMLOmV2ZW50 + LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNv + bg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJy + ZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgZGlyZWN0aW9uIn19LCJwIjoiYWJjZGVmZ2hpamts + bW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3OCJ9gCg/uwAA + AMwAAABXvMge5As6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUH + ABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5k + ZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6Ii4gTGlrZSJ9fSwicCI6 + ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eCJ97qhEmQAAALoAAABXyloLiws6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmlu + Z0NvbnRlbnQiOnsidGV4dCI6IiBpbiJ9fSwicCI6ImFiY2RlZmdoaSJ9lqrL5QAAAMQAAABXjLhV + JQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNh + dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRl + bHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiB0aGUgVUssIn19LCJwIjoiYWJjZGVm + Z2hpamtsbW4ifQTkL/MAAADJAAAAV3QokZQLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0 + YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7 + ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQi + OiIgY2FycyJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXYifRCSMGgAAADnAAAAVwrZAPEL + OmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRp + b24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0 + YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgZHJpdmUgb24gdGhlIn19LCJwIjoiYWJj + ZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVIifQwhTE4AAADHAAAAV8sY + L/ULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGlj + YXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJk + ZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgbGVmdC4gU28ifX0sInAiOiJhYmNk + ZWZnaGlqa2xtbm9wIn3/z4/kAAAA7AAAAFd9CTHgCzpldmVudC10eXBlBwARY29udGVudEJsb2Nr + RGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2 + ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0 + ZXh0IjoiIG1heWJlIGFkZCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVG + R0hJSktMTU5PUFFSU1RVVldYWVoifUeYpYAAAADQAAAAVxnYZGcLOmV2ZW50LXR5cGUHABFjb250 + ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10 + eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250 + ZW50Ijp7InRleHQiOiIgYSBub3RlIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpB + In22xydmAAAA4gAAAFfCOY+BCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRl + bnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50 + QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGFib3V0 + IGJlaW5nIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTiJ9 + XEgpeQAAAOsAAABXzynt8As6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50 + LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJs + b2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBhd2FyZSBv + ZiB0aGUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BR + UlNUVVYifQvDOWIAAADLAAAAVw7owvQLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06 + Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNv + bnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIg + bG9jYWwgdHJhZmZpYyBkaXJlY3Rpb24ifX0sInAiOiJhYmNkZSJ9qyoJKgAAAOkAAABXtem+kAs6 + ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv + bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRh + Ijp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6Ii4gQWxzbyJ9fSwicCI6ImFiY2RlZmdoaWpr + bG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowIn1hY9sAAAAA3QAAAFfh + SKDWCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxp + Y2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwi + ZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiLCBkaXN0cmFjdGlvbnMifX0sInAi + OiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkcifdVswFYAAADqAAAAV/JJxEALOmV2 + ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24v + anNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6 + eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgbGlrZSJ9fSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIifQKDbcIAAADvAAAAVzqp + SzALOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGlj + YXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJk + ZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgdXNpbmcgYSJ9fSwicCI6ImFiY2Rl + ZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNCJ98NdS + cAAAAPkAAABX1QkpEgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5 + cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2Nr + SW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBwaG9uZSB3aGls + ZSBjcm9zc2luZyJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktM + TU5PUFFSU1RVVldYWVowMSJ9WLSrfgAAAOUAAABXcBlTkQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQi + OnsidGV4dCI6Ii4gRW0ifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdI + SUpLTE1OT1BRUlNUVVZXWFkifRPUOj8AAADWAAAAV5aYkccLOmV2ZW50LXR5cGUHABFjb250ZW50 + QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBl + BwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50 + Ijp7InRleHQiOiJwaGFzaXplIHRoZSJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6 + QUJDIn2447dDAAAA5wAAAFcK2QDxCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNv + bnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250 + ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGlt + cG9ydGFuY2Ugb2Ygc3RheWluZyJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJD + REVGR0hJIn1rMsQzAAAA5QAAAFdwGVORCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGEN + OmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJj + b250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0Ijoi + IGZvY3VzZWQifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1O + T1BRUlNUVSJ9mpX8wAAAANMAAABXXngetws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6 + IiBhbmQgbm90In19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkMifVE02hIAAAC8 + AAAAV0Ua/isLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQ + YXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4 + IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgYmVpbmcifX0sInAiOiJh + YmNkZWZnaCJ9zv24YAAAAPYAAABXV1m+wws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6 + IiBkaXN0cmFjdGVkLlxuXG4ifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RF + RkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMyJ9AA7gAQAAAN4AAABXpujaBgs6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmlu + Z0NvbnRlbnQiOnsidGV4dCI6IldoYXQifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5 + ekFCQ0RFRkdISUpLTE1OT1BRUiJ9Ni1iTQAAANIAAABXYxg3Bws6ZXZlbnQtdHlwZQcAEWNvbnRl + bnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5 + cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRl + bnQiOnsidGV4dCI6IiBhYm91dCBjaGlsZHJlbiJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0 + dSJ9nyHypQAAAMgAAABXSUi4JAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250 + ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVu + dEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBvciJ9 + fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3In3Yw3jMAAAA4QAAAFeFmfVRCzpldmVudC10 + eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N + Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVh + c29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHBlb3BsZSJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3Bx + cnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSIn03u0oHAAAA3wAAAFebiPO2CzpldmVudC10eXBl + BwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1l + c3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29u + aW5nQ29udGVudCI6eyJ0ZXh0IjoiIHdpdGggZGlzYWJpbGl0aWVzPyJ9fSwicCI6ImFiY2RlZmdo + aWprbG1ub3BxcnN0dXZ3eHl6QUJDRCJ9sIvUggAAAOUAAABXcBlTkQs6ZXZlbnQtdHlwZQcAEWNv + bnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdl + LXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0Nv + bnRlbnQiOnsidGV4dCI6IiBNYXliZSBtZW50aW9uIHVzaW5nIn19LCJwIjoiYWJjZGVmZ2hpamts + bW5vcHFyc3R1dnd4eXpBQkNERUZHSEkifc/5XFgAAADBAAAAV0RY2lULOmV2ZW50LXR5cGUHABFj + b250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2Fn + ZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdD + b250ZW50Ijp7InRleHQiOiIgcGVkZXN0cmlhbiJ9fSwicCI6ImFiY2RlZmdoIn0Emd0eAAAA5gAA + AFc3uSlBCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFw + cGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6 + MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGJyaWRnZXMifX0sInAiOiJh + YmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVYifQh+aMoAAADt + AAAAV0BpGFALOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQ + YXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4 + IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgb3IgdHVubmVscyJ9fSwi + cCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVoi + fcIdYMAAAADpAAAAV7XpvpALOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVu + dC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRC + bG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgaWYgYXZh + aWxhYmxlLiJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5P + UFFSUyJ9B7KbdAAAAOUAAABXcBlTkQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpj + b250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29u + dGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBB + bHNvLCBtYWtpbmcifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpL + TE1OT1AifU5ZwWkAAADfAAAAV5uI87YLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06 + Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNv + bnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIg + ZXllIGNvbnRhY3Qgd2l0aCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVG + In3tTvuAAAAAvgAAAFc/2q1LCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRl + bnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50 + QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGRyaXZl + cnMgdG8ifX0sInAiOiJhYmNkZSJ9SZGYzwAAAMIAAABXA/ighQs6ZXZlbnQtdHlwZQcAEWNvbnRl + bnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5 + cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRl + bnQiOnsidGV4dCI6IiBlbnN1cmUgdGhleSBzZWUifX0sInAiOiJhYmNkIn0T2UymAAAA8QAAAFfl + eWLTCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxp + Y2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwi + ZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHlvdS4gQnV0In19LCJwIjoiYWJj + ZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NSJ9 + b7fvfgAAAOIAAABXwjmPgQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50 + LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJs + b2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBub3QifX0s + InAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVYifTEJ + 9MIAAADaAAAAV1NofMYLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10 + eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9j + a0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgYWxsIGRyaXZl + cnMifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRiJ9uX9mmQAAAN4AAABX + pujaBgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBs + aWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAs + ImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBtaWdodCBtYWtlIn19LCJwIjoi + YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKSyJ9fJ6yvgAAAOAAAABXuPnc4Qs6 + ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv + bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRh + Ijp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBleWUgY29udGFjdCwifX0sInAiOiJhYmNk + ZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLIn3R0F+HAAAA3wAAAFebiPO2CzpldmVu + dC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pz + b24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsi + cmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHNvIG1heWJlIHRoYXQifX0sInAiOiJhYmNkZWZn + aGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISSJ9aYjZKQAAANUAAABX0TjrFws6ZXZlbnQtdHlw + ZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTpt + ZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNv + bmluZ0NvbnRlbnQiOnsidGV4dCI6IidzIG5vdCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0 + dXZ3eHl6QUJDREVGRyJ9g85FMwAAAN8AAABXm4jztgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9j + a0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVl + dmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsi + dGV4dCI6IiBhbHdheXMifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdI + SUpLTE1OT1AifXREBLsAAAC+AAAAVz/arUsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0 + YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7 + ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQi + OiIgcmVsaWFibGUuXG5cbiJ9fSwicCI6ImFiIn3AlEqaAAAA2AAAAFcpqC+mCzpldmVudC10eXBl + BwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1l + c3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29u + aW5nQ29udGVudCI6eyJ0ZXh0IjoiT2gifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5 + ekFCQ0RFRkdISUpLTE1OIn1oV3/4AAAA7wAAAFc6qUswCzpldmVudC10eXBlBwARY29udGVudEJs + b2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcA + BWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6 + eyJ0ZXh0IjoiLCBhbmQifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdI + SUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1NjcifcNJYAIAAADyAAAAV6LZGAMLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25p + bmdDb250ZW50Ijp7InRleHQiOiIgamF5d2FsayJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0 + dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU2NyJ9K0zSTgAAANMAAABXXnge + tws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNh + dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRl + bHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6ImluZy4gU2hvdWxkIn19LCJwIjoiYWJj + ZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoifUNX9B0AAADcAAAAV9woiWYLOmV2ZW50LXR5cGUHABFj + b250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2Fn + ZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdD + b250ZW50Ijp7InRleHQiOiIgSSBtZW50aW9uIHRoYXQifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9w + cXJzdHV2d3h5ekFCQ0RFIn0hOADUAAAA3wAAAFebiPO2CzpldmVudC10eXBlBwARY29udGVudEJs + b2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcA + BWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6 + eyJ0ZXh0IjoiIGl0J3MgaWxsZWdhbCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6 + QUJDREVGR0hJSiJ9G3veowAAAMcAAABXyxgv9Qs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0Rl + bHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVu + dHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4 + dCI6IiBpbiBzb21lIHBsYWNlcyJ9fSwicCI6ImFiY2RlZmdoaWoifV9HD34AAADpAAAAV7XpvpAL + OmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRp + b24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0 + YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgYW5kIHNhZmVyIn19LCJwIjoiYWJjZGVm + Z2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWVyJ9Y3plxQAAANsAAABX + bghVdgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBs + aWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAs + ImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiB0byB1c2UifX0sInAiOiJhYmNk + ZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTCJ9Lv6e4AAAAMYAAABX9ngGRQs6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7 + InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBjcm9zc3dhbGtzPyJ9fSwicCI6ImFiY2RlZmdo + aWprbCJ9mUlQPQAAANEAAABXJLhN1ws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpj + b250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29u + dGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBZ + ZXMifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFIn2HzL9hAAAAwQAAAFdE + WNpVCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxp + Y2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwi + ZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiLCB0aGF0In19LCJwIjoiYWJjZGVm + Z2hpamtsbSJ9/6EOuwAAAOUAAABXcBlTkQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6 + IidzIGltcG9ydGFudCBmb3IifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RF + RkdISUpLTE0ifatDejYAAADEAAAAV4y4VSULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0 + YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7 + ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQi + OiIgbGVnYWwifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wIn02m2MZAAAA0gAAAFdjGDcHCzpldmVu + dC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pz + b24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsi + cmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGFuZCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3Bx + cnN0dXZ3eHl6QUJDREVGIn0kHSLHAAAA8AAAAFfYGUtjCzpldmVudC10eXBlBwARY29udGVudEJs + b2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcA + BWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6 + eyJ0ZXh0IjoiIHNhZmV0eSByZWFzb25zLiJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 + eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYIn1cPkKEAAAA9gAAAFdXWb7DCzpldmVudC10eXBl + BwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1l + c3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29u + aW5nQ29udGVudCI6eyJ0ZXh0IjoiIEFsc28sIGV2ZW4ifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9w + cXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1Njc4In3FFMGvAAAAwAAA + AFd5OPPlCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFw + cGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6 + MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGlmIHRoZSB3YWxrIn19LCJw + IjoiYWJjZGVmIn2mye5iAAAAzQAAAFeBqDdUCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVs + dGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50 + eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0 + IjoiIHNpZ25hbCBpcyBvbiJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxciJ9zBn3fgAAANYAAABX + lpiRxws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBs + aWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAs + ImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiwgY2hlY2sifX0sInAiOiJhYmNk + ZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkcifd5XknkAAAD1AAAAVxD5xBMLOmV2ZW50LXR5 + cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06 + bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFz + b25pbmdDb250ZW50Ijp7InRleHQiOiIgZm9yIHR1cm5pbmcifX0sInAiOiJhYmNkZWZnaGlqa2xt + bm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1NiJ9nCEOkgAAANAA + AABXGdhkZws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBh + cHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgi + OjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiB2ZWhpY2xlcyJ9fSwicCI6 + ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHkifRrG7tsAAADTAAAAV154HrcLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25p + bmdDb250ZW50Ijp7InRleHQiOiIgdGhhdCBtaWdodCBub3QifX0sInAiOiJhYmNkZWZnaGlqa2xt + bm9wcXJzdHV2In1KyZIMAAAA1wAAAFer+Lh3CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVs + dGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50 + eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0 + IjoiIHN0b3AifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUoifepR + NDIAAADdAAAAV+FIoNYLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10 + eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9j + a0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIuIEIifX0sInAi + OiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUiJ9x8G2NQAAAMwA + AABXvMge5As6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBh + cHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgi + OjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6ImljeWNsZXMgYW5kIn19LCJw + IjoiYWJjZGVmZ2hpamtsbW5vcHFycyJ9YDKTswAAAPMAAABXn7kxsws6ZXZlbnQtdHlwZQcAEWNv + bnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdl + LXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0Nv + bnRlbnQiOnsidGV4dCI6IiBtb3RvcmN5Y2xlcyJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0 + dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNCJ9gkmI6gAAAM8AAABX+2hkNAs6 + ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv + bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRh + Ijp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBjYW4gYmUifX0sInAiOiJhYmNkZWZnaGlq + a2xtbm9wcXJzdHV2d3h5eiJ9VdeX+gAAANIAAABXYxg3Bws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQi + OnsidGV4dCI6IiBxdWlldGVyIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQiJ9 + 1jeKqwAAAMYAAABX9ngGRQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50 + LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJs + b2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBhbmQifX0s + InAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdCJ9ItS9gQAAAPIAAABXotkYAws6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmlu + Z0NvbnRlbnQiOnsidGV4dCI6IiBoYXJkZXIgdG8gaGVhciJ9fSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowIn3TuvzZAAAAzQAAAFeBqDdU + CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0 + aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVs + dGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiLCBzbyByZW1pbmQifX0sInAiOiJhYmNk + ZWZnaGlqa2xtbm9wcXJzdCJ93g0TfwAAAOwAAABXfQkx4As6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQi + OnsidGV4dCI6IiB0byJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJ + SktMTU5PUFFSU1RVVldYWVowMTIzNDU2In2UKfXeAAAA6AAAAFeIiZcgCzpldmVudC10eXBlBwAR + Y29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3Nh + Z2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5n + Q29udGVudCI6eyJ0ZXh0IjoiIGxpc3RlbiJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 + eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWSJ9GqzNlQAAAMkAAABXdCiRlAs6ZXZlbnQtdHlw + ZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTpt + ZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNv + bmluZ0NvbnRlbnQiOnsidGV4dCI6IiBhcyJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 + eCJ9ACDJqwAAAOgAAABXiImXIAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250 + ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVu + dEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiB3ZWxs + IGFzIGxvb2sifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1O + T1BRUlMifVI+3FsAAADvAAAAVzqpSzALOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06 + Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNv + bnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIu + XG5cbldhaXQifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1O + T1BRUlNUVVZXWFlaMDEyMyJ9jQOB5AAAAPMAAABXn7kxsws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQi + OnsidGV4dCI6Iiwgd2hhdCBhYm91dCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6 + QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNCJ9NfbdswAAANAAAABXGdhkZws6ZXZlbnQt + dHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29u + DTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJl + YXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBhdCBuaWdodCJ9fSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3eHkifT4TVNAAAADaAAAAV1NofMYLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tE + ZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZl + bnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRl + eHQiOiI/IFcifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1O + TyJ9HlUKIgAAAPoAAABXkqlTwgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250 + ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVu + dEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6ImVhcmlu + ZyByZWZsZWN0aXZlIGNsb3RoaW5nIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpB + QkNERUZHSElKS0xNTk9QUVJTVFVWV1giffPmSAUAAADbAAAAV24IVXYLOmV2ZW50LXR5cGUHABFj + b250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2Fn + ZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdD + b250ZW50Ijp7InRleHQiOiIgb3IgY2FycnlpbmcifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJz + dHV2d3h5ekFCQ0RFRkcifQ8LclkAAADoAAAAV4iJlyALOmV2ZW50LXR5cGUHABFjb250ZW50Qmxv + Y2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAF + ZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7 + InRleHQiOiIgYSBsaWdodCB0byJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJD + REVGR0hJSktMTU5PUFFSU1RVIn08yzWbAAAA6wAAAFfPKe3wCzpldmVudC10eXBlBwARY29udGVu + dEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlw + ZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVu + dCI6eyJ0ZXh0IjoiIGJlIG1vcmUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFC + Q0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMCJ9BpdpIgAAAMkAAABXdCiRlAs6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmlu + Z0NvbnRlbnQiOnsidGV4dCI6IiB2aXNpYmxlLiBUaGF0In19LCJwIjoiYWJjZGVmZ2hpamtsbSJ9 + EpNjEgAAALoAAABXyloLiws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50 + LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJs + b2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IidzIGEgZ29v + ZCJ9fSwicCI6ImFiYyJ9Cs8BTAAAAMUAAABXsdh8lQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9j + a0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVl + dmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsi + dGV4dCI6IiBwb2ludC4gQWxzbyJ9fSwicCI6ImFiY2RlZmdoaWprIn32XMTrAAAA7AAAAFd9CTHg + CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0 + aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVs + dGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiLCBjcm9zc2luZyJ9fSwicCI6ImFiY2Rl + ZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVoifbmCmw0AAADO + AAAAV8YITYQLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQ + YXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4 + IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgaW4gZ3JvdXBzIn19LCJw + IjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1diJ9dbw9awAAANQAAABX7FjCpws6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmlu + Z0NvbnRlbnQiOnsidGV4dCI6IiBpZiBwb3NzaWJsZSwifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9w + cXJzdHV2d3h5In11ExO8AAAAzQAAAFeBqDdUCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVs + dGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50 + eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0 + IjoiIGFzIG1vcmUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2dyJ9cgSBTwAAAMcAAABX + yxgv9Qs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBs + aWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAs + ImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBwZW9wbGUgYXJlIG1vcmUifX0s + InAiOiJhYmNkZWZnaGkifRhlc1QAAADzAAAAV5+5MbMLOmV2ZW50LXR5cGUHABFjb250ZW50Qmxv + Y2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAF + ZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7 + InRleHQiOiIgdmlzaWJsZS4ifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RF + RkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1NjcifdqwdXUAAADpAAAAV7XpvpALOmV2ZW50LXR5 + cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06 + bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFz + b25pbmdDb250ZW50Ijp7InRleHQiOiIgQnV0IGR1cmluZyJ9fSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVViJ92oLc9AAAANwAAABX3CiJZgs6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7 + InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBDT1ZJRCJ9fSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU4ifZ9DVvUAAADlAAAAV3AZU5ELOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25p + bmdDb250ZW50Ijp7InRleHQiOiIsIG1heWJlIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1 + dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWIn2Boy7VAAABBQAAAFeTkUfrCzpldmVudC10eXBl + BwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1l + c3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29u + aW5nQ29udGVudCI6eyJ0ZXh0IjoiIHNvY2lhbCBkaXN0YW5jaW5nIGFmZmVjdHMifX0sInAiOiJh + YmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1 + Njc4In3cFnthAAAA4gAAAFfCOY+BCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNv + bnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250 + ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHRo + YXQ/IE5vdCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5P + UCJ9b3UCCwAAAOIAAABXwjmPgQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250 + ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVu + dEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBzdXJl + IGlmIHRoYXQifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE0i + fSWc/xAAAADIAAAAV0lIuCQLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVu + dC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRC + bG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIncyBzdGls + bCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxciJ9c9q2LQAAAMAAAABXeTjz5Qs6ZXZlbnQtdHlw + ZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTpt + ZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNv + bmluZ0NvbnRlbnQiOnsidGV4dCI6IiBhIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcCJ90NMxvgAA + AO0AAABXQGkYUAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUH + ABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5k + ZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBjb25jZXJuLCJ9fSwi + cCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVow + MSJ9iqaYkAAAAMQAAABXjLhVJQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250 + ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVu + dEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBidXQg + bWF5YmUgc2tpcCJ9fSwicCI6ImFiY2RlZmcifa+YcOEAAADUAAAAV+xYwqcLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25p + bmdDb250ZW50Ijp7InRleHQiOiIgdGhhdCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 + eHl6QUJDREVGRyJ9Gl4xkAAAAOMAAABX/1mmMQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0Rl + bHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVu + dHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4 + dCI6IiBwYXJ0IHVubGVzcyBuZWNlc3NhcnkifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 + d3h5ekFCQ0RFIn3IVo3oAAAA3AAAAFfcKIlmCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVs + dGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50 + eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0 + IjoiLlxuXG5MZXQifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpL + TCJ9qNCCGgAAAMsAAABXDujC9As6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250 + ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVu + dEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBtZSBv + dXRsaW5lIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyIn3dZEA0AAAAxgAAAFf2eAZFCzpldmVu + dC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pz + b24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsi + cmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHRoZSBzdGVwczoifX0sInAiOiJhYmNkZWZnaGlq + a2xtIn2brGFbAAAA3AAAAFfcKIlmCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNv + bnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250 + ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIDEu + In19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUSJ9md+Z + /wAAAM4AAABXxghNhAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5 + cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2Nr + SW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBGaW5kIGEgc2Fm + ZSJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0In0sWj14AAAAxQAAAFex2HyVCzpldmVudC10 + eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N + Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVh + c29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGNyb3NzaW5nIn19LCJwIjoiYWJjZGVmZ2hpamtsbW4i + fWS+I2sAAAC8AAAAV0Ua/isLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVu + dC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRC + bG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgcG9pbnQu + ICJ9fSwicCI6ImFiY2RlZiJ9GCMjogAAAM4AAABXxghNhAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQi + OnsidGV4dCI6IjIuIE9ic2VydmUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2In3RCgP+ + AAAAzAAAAFe8yB7kCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlw + ZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJ + bmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHRyYWZmaWMgc2ln + bmFscy4ifX0sInAiOiJhYmNkZWZnaGlqa2xtIn1UtKNpAAAA5wAAAFcK2QDxCzpldmVudC10eXBl + BwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1l + c3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29u + aW5nQ29udGVudCI6eyJ0ZXh0IjoiIDMuIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4 + eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxIn0Grvq1AAAA2wAAAFduCFV2CzpldmVudC10 + eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N + Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVh + c29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIExvb2sgYm90aCB3YXlzIn19LCJwIjoiYWJjZGVmZ2hp + amtsbW5vcHFyc3R1dnd4eXpBQkNEIn2/5XzMAAAA6QAAAFe16b6QCzpldmVudC10eXBlBwARY29u + dGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2Ut + dHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29u + dGVudCI6eyJ0ZXh0IjoiLiAifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RF + RkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQifcxZ61kAAADXAAAAV6v4uHcLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25p + bmdDb250ZW50Ijp7InRleHQiOiI0LiBNYWtlIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1 + dnd4eXpBQkNERUZHSCJ9GlJzSwAAAMMAAABXPpiJNQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9j + a0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVl + dmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsi + dGV4dCI6IiBzdXJlIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcCJ9Cx5VYgAAAMgAAABXSUi4JAs6 + ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv + bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRh + Ijp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBpdCJ9fSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3In3d1PVDAAAA1wAAAFer+Lh3CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVs + dGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50 + eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0 + IjoiJ3Mgc2FmZS4ifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkcifSB0 + 85YAAADCAAAAVwP4oIULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10 + eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9j + a0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgNS4ifX0sInAi + OiJhYmNkZWZnaGlqa2xtbm9wcSJ9xyCfSAAAANgAAABXKagvpgs6ZXZlbnQtdHlwZQcAEWNvbnRl + bnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5 + cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRl + bnQiOnsidGV4dCI6IiBTdGF5IHZpc2libGUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 + d3h5ekFCQyJ9DTOxvAAAALUAAABXSAqcWgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6 + Ii4gNiJ9fSwicCI6ImFiY2QifcEqgaMAAADHAAAAV8sYL/ULOmV2ZW50LXR5cGUHABFjb250ZW50 + QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBl + BwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50 + Ijp7InRleHQiOiIuIFdhbGsifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzIn2oDrxYAAAAwQAA + AFdEWNpVCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFw + cGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6 + MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHN0cmFpZ2h0In19LCJwIjoi + YWJjZGVmZ2hpaiJ9fenSsQAAAMoAAABXM4jrRAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0Rl + bHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVu + dHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4 + dCI6IiBhY3Jvc3MuIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3QifdL/nvcAAADVAAAAV9E4 + 6xcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGlj + YXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJk + ZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgNyJ9fSwicCI6ImFiY2RlZmdoaWpr + bG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSksifb1icjoAAADxAAAAV+V5YtMLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25p + bmdDb250ZW50Ijp7InRleHQiOiIuIFN0YXkifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 + d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1Njc4In3XEF4wAAAA4QAAAFeFmfVR + CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0 + aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVs + dGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGFsZXJ0LiBNYXliZSJ9fSwicCI6ImFi + Y2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMIn3jVBmXAAAA4wAAAFf/WaYxCzpl + dmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9u + L2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEi + OnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGFkZCB0aXBzIn19LCJwIjoiYWJjZGVmZ2hp + amtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVIifUFTvRUAAAC2AAAAVw+q5ooLOmV2 + ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24v + anNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6 + eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgZm9yIn19LCJwIjoiYWJjZCJ9kRkLeAAAAOgA + AABXiImXIAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBh + cHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgi + OjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBkaWZmZXJlbnQgc2l0dWF0 + aW9ucyJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSksifc6yCb4A + AADUAAAAV+xYwqcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgbGlrZSB1biJ9fSwi + cCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDRCJ9DBPSjwAAAOEAAABXhZn1UQs6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7 + InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6Im1hcmtlZCJ9fSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSUyJ9PxViNwAAANkAAABXFMgGFgs6ZXZlbnQt + dHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29u + DTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJl + YXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBjcm9zc2luZ3MsIGludGVyc2VjdGlvbnMifX0sInAi + OiJhYmNkZWZnaGlqa2xtbm9wcXIiffalLU8AAADlAAAAV3AZU5ELOmV2ZW50LXR5cGUHABFjb250 + ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10 + eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250 + ZW50Ijp7InRleHQiOiIgd2l0aCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJD + REVGR0hJSktMTU5PUFFSU1RVVldYIn1XUpEiAAAA8AAAAFfYGUtjCzpldmVudC10eXBlBwARY29u + dGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2Ut + dHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29u + dGVudCI6eyJ0ZXh0IjoiIHNpZ25hbHMifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5 + ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1In1c01Y8AAAA4AAAAFe4+dzhCzpldmVu + dC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pz + b24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsi + cmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiLCBldGMuXG5cbiJ9fSwicCI6ImFiY2RlZmdoaWpr + bG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU4ifYHC5vgAAADkAAAAV015eiELOmV2ZW50LXR5 + cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06 + bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFz + b25pbmdDb250ZW50Ijp7InRleHQiOiJBbHNvIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1 + dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1gifUKWWEcAAADdAAAAV+FIoNYLOmV2ZW50LXR5 + cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06 + bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFz + b25pbmdDb250ZW50Ijp7InRleHQiOiIsIGluY2x1ZGUgc2FmZXR5In19LCJwIjoiYWJjZGVmZ2hp + amtsbW5vcHFyc3R1dnd4eXpBQkNERSJ9uHOggwAAANYAAABXlpiRxws6ZXZlbnQtdHlwZQcAEWNv + bnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdl + LXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0Nv + bnRlbnQiOnsidGV4dCI6IiB0aXBzIGxpa2UgYXZvaWRpbmcifX0sInAiOiJhYmNkZWZnaGlqa2xt + bm9wcXJzdHUifQ23rAUAAADYAAAAVymoL6YLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0 + YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7 + ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQi + OiIgZGlzdHJhY3Rpb25zLCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUIifUdI + XBsAAADBAAAAV0RY2lULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10 + eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9j + a0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgd2F0Y2hpbmci + fX0sInAiOiJhYmNkZWZnaGlqIn0lVxXqAAAAxQAAAFex2HyVCzpldmVudC10eXBlBwARY29udGVu + dEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlw + ZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVu + dCI6eyJ0ZXh0IjoiIGZvciB0dXJuaW5nIn19LCJwIjoiYWJjZGVmZ2hpamsifftPfX4AAADUAAAA + V+xYwqcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBw + bGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4Ijow + LCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgdmVoaWNsZXMsIGFuZCJ9fSwi + cCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eCJ9G4en+gAAAOEAAABXhZn1UQs6ZXZlbnQtdHlw + ZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTpt + ZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNv + bmluZ0NvbnRlbnQiOnsidGV4dCI6IiBiZWluZyBjYXV0aW91cyJ9fSwicCI6ImFiY2RlZmdoaWpr + bG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSiJ9MQen8QAAALwAAABXRRr+Kws6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmlu + Z0NvbnRlbnQiOnsidGV4dCI6IiBhdCBuaWdodC4ifX0sInAiOiJhYmNkIn3H8rv6AAABAQAAAFdm + EeErCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxp + Y2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwi + ZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIE1heWJlIG1lbnRpb24gcGVkZXN0 + cmlhbiJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFS + U1RVVldYWVowMTIzNDUifbJKbQ0AAADeAAAAV6bo2gYLOmV2ZW50LXR5cGUHABFjb250ZW50Qmxv + Y2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAF + ZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7 + InRleHQiOiIgcmlnaHRzIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZH + SElKS0xNTk8ifZO2ir8AAAC6AAAAV8paC4sLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0 + YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7 + ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQi + OiIgYnV0In19LCJwIjoiYWJjZGVmZ2gifVsJiO0AAAC5AAAAV436cVsLOmV2ZW50LXR5cGUHABFj + b250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2Fn + ZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdD + b250ZW50Ijp7InRleHQiOiIgYWxzbyB0aGUifX0sInAiOiJhYiJ9cAKt7QAAAMcAAABXyxgv9Qs6 + ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv + bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRh + Ijp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBuZWVkIn19LCJwIjoiYWJjZGVmZ2hpamts + bW5vcHFyc3QifRveHT0AAADpAAAAV7XpvpALOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0 + YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7 + ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQi + OiIgdG8gYmUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1O + T1BRUlNUVVZXWFlaMCJ9gaSOZAAAAN0AAABX4Uig1gs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9j + a0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVl + dmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsi + dGV4dCI6IiBjYXV0aW91cyByZWdhcmRsZXNzIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1 + dnd4eXpBIn2GwrudAAAA5AAAAFdNeXohCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGEN + OmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJj + b250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0Ijoi + LiJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RV + VldYWVowIn3/wAcbAAAAvwAAAFcCuoT7CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGEN + OmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJj + b250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0Ijoi + IFNob3VsZCJ9fSwicCI6ImFiY2RlZmdoaWoifeVV04sAAADbAAAAV24IVXYLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25p + bmdDb250ZW50Ijp7InRleHQiOiIgSSBtZW50aW9uIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFy + c3R1dnd4eXpBQkNERUZHSEkifTln190AAADYAAAAVymoL6YLOmV2ZW50LXR5cGUHABFjb250ZW50 + QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBl + BwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50 + Ijp7InRleHQiOiIgdXNpbmcifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RF + RkdISUoiffmgYSAAAADQAAAAVxnYZGcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06 + Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNv + bnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIg + cGVkZXN0cmlhbiJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3In0TQ5H3AAAAuQAAAFeN + +nFbCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxp + Y2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwi + ZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGJyaWRnZXMifX0sInAiOiJhYmMi + fZ/vtisAAADdAAAAV+FIoNYLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVu + dC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRC + bG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgb3IgdW5k + ZXIifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTCJ9SjcQZQAA + AOEAAABXhZn1UQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUH + ABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5k + ZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6InBhc3NlcyBhcyJ9fSwi + cCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUCJ9fc+WywAAAMAA + AABXeTjz5Qs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBh + cHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgi + OjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBhbHRlcm5hdGl2ZXM/In19 + LCJwIjoiYWJjZCJ9ce3hFgAAAPQAAABXLZntows6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0Rl + bHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVu + dHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4 + dCI6IiBZZXMsIHRoYXQifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdI + SUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1NjcifRWIPnsAAADZAAAAVxTIBhYLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25p + bmdDb250ZW50Ijp7InRleHQiOiIncyBhIGdvb2QifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJz + dHV2d3h5ekFCQ0RFRkdIIn3r4BKeAAAAvgAAAFc/2q1LCzpldmVudC10eXBlBwARY29udGVudEJs + b2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcA + BWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6 + eyJ0ZXh0IjoiIGlkZWEuXG5cbiJ9fSwicCI6ImFiY2RlZiJ9Hd+xqgAAAMgAAABXSUi4JAs6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7 + InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IldhaXQsIGJ1dCJ9fSwicCI6ImFiY2RlZmdoaWpr + bG1ub3BxIn19G6gEAAAA4AAAAFe4+dzhCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGEN + OmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJj + b250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0Ijoi + IGluIHNvbWUgY291bnRyaWVzIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE + RUYifffH7j0AAAC8AAAAV0Ua/isLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29u + dGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRl + bnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIsIGV2 + ZW4ifX0sInAiOiJhYmNkZWZnaCJ9NZFj9gAAAMoAAABXM4jrRAs6ZXZlbnQtdHlwZQcAEWNvbnRl + bnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5 + cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRl + bnQiOnsidGV4dCI6IiBpZiB5b3UifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHUifZQFWGoA + AADkAAAAV015eiELOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgaGF2ZSB0aGUgcmln + aHQifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE0ifd0tvAcA + AADnAAAAVwrZAPELOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgb2Ygd2F5LCJ9fSwi + cCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVlcifaz/ + sisAAADsAAAAV30JMeALOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10 + eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9j + a0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgZHJpdmVycyBt + aWdodCBub3QifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1O + T1BRUiJ9LvQwDQAAAOwAAABXfQkx4As6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpj + b250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29u + dGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBz + dG9wLiJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFS + U1RVVldYWVowMTIzIn02wzaAAAAAuAAAAFewmljrCzpldmVudC10eXBlBwARY29udGVudEJsb2Nr + RGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2 + ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0 + ZXh0IjoiIFNvIGl0J3MifX0sInAiOiJhYiJ9BNKb7wAAAMUAAABXsdh8lQs6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmlu + Z0NvbnRlbnQiOnsidGV4dCI6IiBiZXR0ZXIgdG8gYWx3YXlzIn19LCJwIjoiYWJjZGVmIn12jfdD + AAAA3AAAAFfcKIlmCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlw + ZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJ + bmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGVuc3VyZSJ9fSwi + cCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTSJ9GwsVTgAAANMAAABX + Xngetws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBs + aWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAs + ImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiB0aGUifX0sInAiOiJhYmNkZWZn + aGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkcifYwGslEAAADRAAAAVyS4TdcLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25p + bmdDb250ZW50Ijp7InRleHQiOiIgdmVoaWNsZSJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0 + dXZ3eHl6QSJ9YkYWnAAAAMwAAABXvMge5As6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6 + IiBpcyBzdG9wcGluZyBiZWZvcmUifX0sInAiOiJhYmNkZWZnaGlqayJ9DR4IlAAAAPMAAABXn7kx + sws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNh + dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRl + bHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBjcm9zc2luZy4gTWF5YmUifX0sInAi + OiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMCJ9 + VUn6sAAAAPEAAABX5Xli0ws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50 + LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJs + b2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBlbXBoYXNp + emUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNU + VVZXWFlaMDEyMzQifbQA5tkAAADoAAAAV4iJlyALOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tE + ZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZl + bnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRl + eHQiOiIgdGhhdCBldmVuIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZH + SElKS0xNTk9QUVJTVFVWIn0XRMGXAAAAzgAAAFfGCE2ECzpldmVudC10eXBlBwARY29udGVudEJs + b2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcA + BWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6 + eyJ0ZXh0IjoiIGlmIHlvdSJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHkife7nY2sA + AADUAAAAV+xYwqcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgaGF2ZSB0aGUgc2ln + bmFsIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1diJ9liQOwQAAAMoAAABXM4jrRAs6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7 + InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiwgY2hlY2sifX0sInAiOiJhYmNkZWZnaGlqa2xt + bm9wcXJzdHUifSOQD/8AAADEAAAAV4y4VSULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0 + YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7 + ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQi + OiIgdGhhdCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxIn2c8InlAAAA8gAAAFei2RgDCzpldmVu + dC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pz + b24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsi + cmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGNhcnMgYXJlIHN0b3BwaW5nIn19LCJwIjoiYWJj + ZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1gifY4gMiYAAADx + AAAAV+V5YtMLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQ + YXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4 + IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIuXG5cbkFsc28ifX0sInAi + OiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEy + MzQ1In1+jzAsAAAA4wAAAFf/WaYxCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNv + bnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250 + ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiLCB0 + aGUgaW1wb3J0YW5jZSJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJ + SksifbkNUdkAAADhAAAAV4WZ9VELOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29u + dGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRl + bnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgb2Yg + bm90In19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVIi + fV+jS+EAAAC+AAAAVz/arUsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVu + dC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRC + bG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgYXNzdW1p + bmcifX0sInAiOiJhYmNkZWZnIn2e9kTVAAAA4AAAAFe4+dzhCzpldmVudC10eXBlBwARY29udGVu + dEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlw + ZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVu + dCI6eyJ0ZXh0IjoiIHRoYXQgZHJpdmVycyBjYW4ifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJz + dHV2d3h5ekFCQ0RFRkcifSzoLjoAAADPAAAAV/toZDQLOmV2ZW50LXR5cGUHABFjb250ZW50Qmxv + Y2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAF + ZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7 + InRleHQiOiIgc2VlIHlvdS4ifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3gifUJE61EA + AADlAAAAV3AZU5ELOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgU29tZXRpbWVzIn19 + LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTIn2Ggn3b + AAAAvQAAAFd4etebCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlw + ZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJ + bmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGRyaXZlcnMifX0s + InAiOiJhYmNkZWZnIn0hFjWPAAAA7AAAAFd9CTHgCzpldmVudC10eXBlBwARY29udGVudEJsb2Nr + RGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2 + ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0 + ZXh0IjoiIGFyZSJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktM + TU5PUFFSU1RVVldYWVowMTIzNDUifWGtW/AAAADZAAAAVxTIBhYLOmV2ZW50LXR5cGUHABFjb250 + ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10 + eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250 + ZW50Ijp7InRleHQiOiIgZGlzdHJhY3RlZCB0b28ifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJz + dHV2d3h5ekFCIn0gkwSgAAAA5wAAAFcK2QDxCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVs + dGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50 + eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0 + IjoiLiBTbyJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5P + UFFSU1RVVldYWVowIn3D32TqAAAAvgAAAFc/2q1LCzpldmVudC10eXBlBwARY29udGVudEJsb2Nr + RGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2 + ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0 + ZXh0IjoiIGJlaW5nIn19LCJwIjoiYWJjZGVmZ2hpaiJ9xak6xgAAAO0AAABXQGkYUAs6ZXZlbnQt + dHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29u + DTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJl + YXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBwcm9hY3RpdmUgaW4ifX0sInAiOiJhYmNkZWZnaGlq + a2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWCJ94W5AzgAAAPcAAABXajmX + cws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNh + dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRl + bHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBlbnN1cmluZyBzYWZldHkuXG5cbiJ9 + fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldY + WVoifRuYPhcAAAC+AAAAVz/arUsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29u + dGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRl + bnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiJMZXQi + fX0sInAiOiJhYmNkZWZnaGlqa2xtIn03Av6BAAAA7wAAAFc6qUswCzpldmVudC10eXBlBwARY29u + dGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2Ut + dHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29u + dGVudCI6eyJ0ZXh0IjoiIG1lIGNoZWNrIGlmIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1 + dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAifaF+5RAAAADAAAAAV3k48+ULOmV2ZW50 + LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNv + bg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJy + ZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgSSBtaXNzZWQifX0sInAiOiJhYmNkZWZnaGkifW/V + aHMAAAD1AAAAVxD5xBMLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10 + eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9j + a0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgYW55dGhpbmcu + In19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVW + V1hZWjAxMjM0NTY3OCJ9IhIQpwAAAPQAAABXLZntows6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9j + a0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVl + dmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsi + dGV4dCI6IiBNYXliZSB0aGUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RF + RkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1Njcifbw3PygAAADAAAAAV3k48+ULOmV2ZW50LXR5 + cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06 + bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFz + b25pbmdDb250ZW50Ijp7InRleHQiOiIgYmFzaWMifX0sInAiOiJhYmNkZWZnaGlqa2wifbCrSvYA + AADrAAAAV88p7fALOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgc3RlcHMgYXJlIn19 + LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZ + In0vU1FVAAAA7gAAAFcHyWKACzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRl + bnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50 + QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGNvdmVy + ZWQifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNU + VVZXWFlaMDEyMyJ9X/09mQAAAPMAAABXn7kxsws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0Rl + bHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVu + dHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4 + dCI6IiwgYnV0IGFkZGluZyJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVG + R0hJSktMTU5PUFFSU1RVVldYWVowMTIzNCJ9SC7/7QAAAOAAAABXuPnc4Qs6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmlu + Z0NvbnRlbnQiOnsidGV4dCI6IiB0aGUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5 + ekFCQ0RFRkdISUpLTE1OT1BRUlNUIn3VMT5uAAAAygAAAFcziOtECzpldmVudC10eXBlBwARY29u + dGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2Ut + dHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29u + dGVudCI6eyJ0ZXh0IjoiIGV4dHJhIHRpcHMgbWFrZXMifX0sInAiOiJhYmNkZWZnaGlqayJ9VeEW + mQAAAPQAAABXLZntows6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5 + cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2Nr + SW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBpdCBjb21wcmVo + ZW5zaXZlIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9Q + UVJTVFVWV1hZWjAifVCi/nMAAAC+AAAAVz/arUsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tE + ZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZl + bnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRl + eHQiOiIuIE9rYXkifX0sInAiOiJhYmNkZWZnaGlqIn2r30e3AAAA7wAAAFc6qUswCzpldmVudC10 + eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N + Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVh + c29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiLCBJIHRoaW5rIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5v + cHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjMifRQjBdkAAAC7AAAAV/c6 + IjsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGlj + YXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJk + ZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgdGhhdCdzIGEifX0sInAiOiJhYmNk + In3Xtlk/AAAA1wAAAFer+Lh3CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRl + bnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50 + QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHNvbGlk + IHN0cnVjdHVyZSJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHkifeHF1ycAAADZAAAA + VxTIBhYLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBw + bGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4Ijow + LCJkZWx0YSI6eyJyZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIuIE5vdywifX0sInAiOiJhYmNk + ZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLIn3lAuRKAAAA9gAAAFdXWb7DCzpldmVu + dC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pz + b24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsi + cmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHByZXNlbnQgaXQgaW4ifX0sInAiOiJhYmNkZWZn + aGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1In0yLVKt + AAAA2QAAAFcUyAYWCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlw + ZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJ + bmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGEgY2xlYXIsIn19 + LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSCJ9NxJ6GAAAAPAAAABX2BlL + Yws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNh + dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRl + bHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBzdGVwLWJ5LXN0ZXAifX0sInAiOiJh + YmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMCJ9dgDr + TwAAAPUAAABXEPnEEws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5 + cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2Nr + SW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBtYW5uZXIgd2l0 + aCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RV + VldYWVowMTIzNDU2In3wrykoAAAAvQAAAFd4etebCzpldmVudC10eXBlBwARY29udGVudEJsb2Nr + RGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2 + ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0 + ZXh0IjoiIHNvbWUifX0sInAiOiJhYmNkZWZnaGlqIn2SsvmzAAAA4gAAAFfCOY+BCzpldmVudC10 + eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N + Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVh + c29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIGJ1bGxldCJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3Bx + cnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSUyJ9nUKIGgAAAOoAAABX8knEQAs6ZXZlbnQtdHlw + ZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTpt + ZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNv + bmluZ0NvbnRlbnQiOnsidGV4dCI6IiBwb2ludHMgb3IifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9w + cXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWCJ9antzNwAAAN4AAABXpujaBgs6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7 + InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBudW1iZXJlZCJ9fSwicCI6ImFiY2RlZmdoaWpr + bG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTSJ9pfkMVwAAALkAAABXjfpxWws6ZXZlbnQtdHlw + ZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTpt + ZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNv + bmluZ0NvbnRlbnQiOnsidGV4dCI6IiBsaXN0In19LCJwIjoiYWJjZGVmIn1uej2JAAAA0QAAAFck + uE3XCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxp + Y2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwi + ZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiLiJ9fSwicCI6ImFiY2RlZmdoaWpr + bG1ub3BxcnN0dXZ3eHl6QUJDREVGR0giffb6tfQAAADdAAAAV+FIoNYLOmV2ZW50LXR5cGUHABFj + b250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2Fn + ZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFzb25pbmdD + b250ZW50Ijp7InRleHQiOiIgTWFrZSBzdXJlIHRoZSJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3Bx + cnN0dXZ3eHl6QUJDREVGRyJ9oPq6vwAAAOoAAABX8knEQAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQi + OnsidGV4dCI6IiBsYW5ndWFnZSBpcyBzaW1wbGUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJz + dHV2d3h5ekFCQ0RFRkdISUpLTE1OTyJ9rtz9fAAAAO4AAABXB8ligAs6ZXZlbnQtdHlwZQcAEWNv + bnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdl + LXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0Nv + bnRlbnQiOnsidGV4dCI6IiBhbmQgZWFzeSB0byJ9fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0 + dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVoifciYTqkAAADCAAAAVwP4oIULOmV2ZW50 + LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNv + bg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJy + ZWFzb25pbmdDb250ZW50Ijp7InRleHQiOiIgdW5kZXJzdGFuZCwifX0sInAiOiJhYmNkZWZnaCJ9 + LnVNcgAAAOkAAABXtem+kAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50 + LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJs + b2NrSW5kZXgiOjAsImRlbHRhIjp7InJlYXNvbmluZ0NvbnRlbnQiOnsidGV4dCI6IiBhdm9pZGlu + ZyBqYXJnb24uIn19LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xN + Tk9QIn1bRxglAAAAugAAAFfKWguLCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNv + bnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250 + ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIEFs + In19LCJwIjoiYWJjZGVmZ2hpIn1Dsn5bAAAAyQAAAFd0KJGUCzpldmVudC10eXBlBwARY29udGVu + dEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlw + ZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVu + dCI6eyJ0ZXh0IjoicmlnaHQsIHRpbWUifX0sInAiOiJhYmNkZWZnaGlqa2xtbm9wIn3vJ6tMAAAA + 0QAAAFckuE3XCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcA + EGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRl + eCI6MCwiZGVsdGEiOnsicmVhc29uaW5nQ29udGVudCI6eyJ0ZXh0IjoiIHRvIHB1dCBpdCJ9fSwi + cCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHkifb94p7gAAADIAAAAV0lIuCQLOmV2ZW50LXR5 + cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06 + bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjowLCJkZWx0YSI6eyJyZWFz + b25pbmdDb250ZW50Ijp7InRleHQiOiIgYWxsIHRvZ2V0aGVyLlxuIn19LCJwIjoiYWJjZGVmZ2hp + aiJ9ZP62hQAAAJQAAABWw6yqeAs6ZXZlbnQtdHlwZQcAEGNvbnRlbnRCbG9ja1N0b3ANOmNvbnRl + bnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50 + QmxvY2tJbmRleCI6MCwicCI6ImFiY2RlZmdoaWprbG1ub3AifcqwdEoAAACrAAAAV5fatbkLOmV2 + ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24v + anNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6 + eyJ0ZXh0IjoiXG5cbiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW4ifZZwJeAAAACyAAAAV/oqQEoLOmV2 + ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24v + anNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6 + eyJ0ZXh0IjoiQ3Jvc3NpbmcgdGhlIn0sInAiOiJhYmNkZWZnaGlqa2xtIn0S3ziDAAAAvwAAAFcC + uoT7CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxp + Y2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwi + ZGVsdGEiOnsidGV4dCI6IiBzdHJlZXQgc2FmZWx5IGludm9sdmVzIn0sInAiOiJhYmNkZWZnaGlq + a2xtbm8ifd3NEVsAAADcAAAAV9woiWYLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06 + Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNv + bnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIGNhcmVmdWwifSwicCI6ImFiY2Rl + ZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU2In1C + vEkYAAAAyAAAAFdJSLgkCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQt + dHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50Qmxv + Y2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBvYnNlcnZhdGlvbiJ9LCJwIjoiYWJjZGVmZ2hp + amtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSEkifQlKGx8AAADbAAAAV24IVXYLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0Ijoi + IGFuZCBhd2FyZW5lc3MuIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdI + SUpLTE1OT1BRUlNUVVZXWFkifaNt+HgAAADQAAAAVxnYZGcLOmV2ZW50LXR5cGUHABFjb250ZW50 + QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBl + BwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIEhlcmUncyJ9 + LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWIn2Z + TJn1AAAA2gAAAFdTaHzGCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQt + dHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50Qmxv + Y2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBhIHN0ZXAifSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDUifQ5mrlsAAADOAAAA + V8YITYQLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBw + bGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4Ijox + LCJkZWx0YSI6eyJ0ZXh0IjoiLWJ5LXN0ZXAgZ3VpZGUifSwicCI6ImFiY2RlZmdoaWprbG1ub3Bx + cnN0dXZ3eHl6QUJDREVGR0hJSktMTSJ91JPnzAAAAKQAAABXFYoiaAs6ZXZlbnQtdHlwZQcAEWNv + bnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdl + LXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiI6XG5c + biMjIyJ9LCJwIjoiYWJjIn30rTYbAAAAuQAAAFeN+nFbCzpldmVudC10eXBlBwARY29udGVudEJs + b2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcA + BWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiAqKiJ9LCJwIjoi + YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkMifa5MkDMAAADOAAAAV8YITYQLOmV2ZW50LXR5 + cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06 + bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0 + IjoiQmFzaWMifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5P + UFFSU1RVViJ9V7OWogAAAK4AAABXXzo6yQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgU3RlcHMqKiJ9LCJwIjoiYWJj + ZGVmZ2hpamtsbSJ9pxiWqAAAALoAAABXyloLiws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0Rl + bHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVu + dHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgIFxuMS4ifSwicCI6ImFi + Y2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QSJ9V9JV5QAAANcAAABXq/i4dws6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIg + KipGaW5kIGEifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5P + UFFSU1RVVldYWVowIn0KajbMAAAA3gAAAFem6NoGCzpldmVudC10eXBlBwARY29udGVudEJsb2Nr + RGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2 + ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBTYWZlIFNwb3QifSwi + cCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVow + MTIzNDU2In2SMyPmAAAAngAAAFf+G4JPCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGEN + OmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJj + b250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IioqOiJ9LCJwIjoiYWIifZuELbcA + AADFAAAAV7HYfJULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiICBcbiAgIC0ifSwicCI6ImFiY2RlZmdoaWprbG1ub3Bx + cnN0dXZ3eHl6QUJDREVGR0hJSiJ9Lmut7QAAAMMAAABXPpiJNQs6ZXZlbnQtdHlwZQcAEWNvbnRl + bnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5 + cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgVXNlIGEg + KioifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGRyJ93E10GAAAAOAAAABX + uPnc4Qs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBs + aWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEs + ImRlbHRhIjp7InRleHQiOiJjcm9zc3dhbGsqKiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1 + dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTY3In16SHDIAAAAxwAAAFfLGC/1 + CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0 + aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVs + dGEiOnsidGV4dCI6IiBvciBwZWRlc3RyaWFuIHNpZ25hbCJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5v + cHFyc3R1dnd4eSJ9HgvUlwAAAL8AAABXArqE+ws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0Rl + bHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVu + dHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgaWYgYXZhaWxhYmxlLiJ9 + LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4In1Ih0MYAAAAqwAAAFeX2rW5CzpldmVudC10 + eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N + Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4 + dCI6IiBBdm9pZCBqIn0sInAiOiJhYmNkZWZnaGlqIn3rz3ITAAAAswAAAFfHSmn6CzpldmVudC10 + eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N + Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4 + dCI6ImF5d2Fsa2luZyJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHEiffSvfqAAAACyAAAAV/oqQEoL + OmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRp + b24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0 + YSI6eyJ0ZXh0IjoiLCBhcyBpdCJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyIn2d1i87AAAA3gAA + AFem6NoGCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFw + cGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6 + MSwiZGVsdGEiOnsidGV4dCI6IuKAmXMgaWxsZWdhbCJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFy + c3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0In1RHiUHAAAAvwAAAFcCuoT7 + CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0 + aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVs + dGEiOnsidGV4dCI6IiBpbiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZH + SEkifc22aE4AAAC+AAAAVz/arUsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29u + dGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRl + bnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIG1hbnkgYXJlYXMifSwicCI6ImFiY2Rl + ZmdoaWprbG1ub3BxcnN0dXZ3eHl6In3nJmSgAAAA3wAAAFebiPO2CzpldmVudC10eXBlBwARY29u + dGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2Ut + dHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBhbmQg + bGVzcyJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT + VFVWV1hZWjAxMjM0NTY3OCJ9IXJKLwAAAMsAAABXDujC9As6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgc2FmZS4gIFxu + In0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OIn1i14YbAAAA + twAAAFcyys86CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcA + EGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRl + eCI6MSwiZGVsdGEiOnsidGV4dCI6IiAgIC0ifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 + eHl6In2hIWyyAAAAsAAAAFeA6hMqCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNv + bnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250 + ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBJZiBubyJ9LCJwIjoiYWJjZGVmZ2hp + amtsbW5vcHEifSU7ve8AAADhAAAAV4WZ9VELOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0 + YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7 + ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIGNyb3Nzd2FsayBleGlzdHMi + fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldY + WVowMTIifffR2ugAAAC8AAAAV0Ua/isLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06 + Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNv + bnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiLCBjaG9vc2UifSwicCI6ImFiY2Rl + ZmdoaWprbG1ub3BxcnN0dXZ3eHl6QSJ9U7KWQAAAALUAAABXSAqcWgs6ZXZlbnQtdHlwZQcAEWNv + bnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdl + LXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgYSB3 + ZWxsIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHUifdvGQW8AAADTAAAAV154HrcLOmV2ZW50 + LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNv + bg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0 + ZXh0IjoiLWxpdCBhcmVhIHdpdGgifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJD + REVGR0hJSktMTU5PUFFSIn1zABHiAAAAtQAAAFdICpxaCzpldmVudC10eXBlBwARY29udGVudEJs + b2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcA + BWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBjbGVhciB2aXNp + YmlsaXR5IGluIn0sInAiOiJhYmNkZWZnaCJ9MxXBegAAAMYAAABX9ngGRQs6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIg + Ym90aCBkaXJlY3Rpb25zLlxuXG4ifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eCJ9+Ga2 + xQAAANAAAABXGdhkZws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5 + cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2Nr + SW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIyLiAqKiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFy + c3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1gifUF+YLUAAADVAAAAV9E46xcLOmV2ZW50 + LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNv + bg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0 + ZXh0IjoiQ2hlY2sgVHJhZmZpYyBTaWduYWxzIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 + d3h5ekFCQ0RFRkdISUpLTE0ifVWHrIQAAAC3AAAAVzLKzzoLOmV2ZW50LXR5cGUHABFjb250ZW50 + QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBl + BwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiKio6ICBcbiAg + In0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHUifVlGQL0AAACzAAAAV8dKafoLOmV2ZW50LXR5 + cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06 + bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0 + IjoiIC0gV2FpdCJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFycyJ9XUa9CgAAAKwAAABXJfppqQs6 + ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv + bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRh + Ijp7InRleHQiOiIgZm9yIHRoZSJ9LCJwIjoiYWJjZGVmZ2hpamsifdkpS84AAADNAAAAV4GoN1QL + OmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRp + b24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0 + YSI6eyJ0ZXh0IjoiIFwid2FsayJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE + RUZHSElKS0xNTk9QUVJTIn1XYWCuAAAAuQAAAFeN+nFbCzpldmVudC10eXBlBwARY29udGVudEJs + b2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcA + BWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IlwiIHNpZ25hbCJ9 + LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dncifanzx1IAAADBAAAAV0RY2lULOmV2ZW50LXR5 + cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06 + bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0 + IjoiIG9yIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLIn0dOlFB + AAAArgAAAFdfOjrJCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlw + ZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJ + bmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBncmVlbiBsaWdodCJ9LCJwIjoiYWJjZGVmZ2hpIn2+ + XRPVAAAAzQAAAFeBqDdUCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQt + dHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50Qmxv + Y2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBhdCBpbnRlcnNlY3Rpb25zIn0sInAiOiJhYmNk + ZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISSJ9MuSbiwAAAKAAAABX4AqEqAs6ZXZlbnQt + dHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29u + DTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRl + eHQiOiIuICBcbiJ9LCJwIjoiYWIifRkJfg8AAADKAAAAVzOI60QLOmV2ZW50LXR5cGUHABFjb250 + ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10 + eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiICAgLSBX + YXRjaCJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNIn1M7taH + AAAAuAAAAFewmljrCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlw + ZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJ + bmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBmb3IgY291bnQifSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dSJ9pZ9jgAAAAN4AAABXpujaBgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiJkb3duIHRpbWVycyJ9LCJwIjoi + YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0 + NSJ95bnyTgAAANQAAABX7FjCpws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250 + ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVu + dEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgdG8gZW5zdXJlIHlvdSJ9LCJwIjoiYWJj + ZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTIn2u3jN1AAAA1gAAAFeW + mJHHCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxp + Y2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwi + ZGVsdGEiOnsidGV4dCI6IiBoYXZlIGVub3VnaCB0aW1lIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9w + cXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUiJ9eMb8YgAAANMAAABXXngetws6ZXZlbnQtdHlw + ZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTpt + ZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQi + OiIgdG8gY3Jvc3MuXG5cbiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZH + SElKS0xNTk9QUVIifVIreXsAAADPAAAAV/toZDQLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tE + ZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZl + bnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiMy4gKioifSwicCI6ImFi + Y2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVlcifVP0sDAAAACn + AAAAV1IqWLgLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQ + YXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4 + IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiTG9vayBCb3RoIn0sInAiOiJhYmNkZSJ9kH2gfAAAANAAAABX + GdhkZws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBs + aWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEs + ImRlbHRhIjp7InRleHQiOiIgV2F5cyoqOiAgXG4ifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0 + dXZ3eHl6QUJDREVGR0hJSktMTU5PUFEifYKS4s4AAACyAAAAV/oqQEoLOmV2ZW50LXR5cGUHABFj + b250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2Fn + ZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiICAg + LSAqKiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyIn1p9sy7AAAAsQAAAFe9ijqaCzpldmVudC10 + eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N + Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4 + dCI6IkxlZnQtUmlnaHQifSwicCI6ImFiY2RlZmdoaWprbG1uIn1IzsZWAAAApgAAAFdvSnEICzpl + dmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9u + L2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEi + OnsidGV4dCI6Ii1MZWZ0Kio6In0sInAiOiJhYmNkZSJ9HoYWugAAAL4AAABXP9qtSws6ZXZlbnQt + dHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29u + DTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRl + eHQiOiIgR2xhbmNlIGxlZnQifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHkifWVqmJMA + AACqAAAAV6q6nAkLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiLCByaWdodCJ9LCJwIjoiYWJjZGVmZ2hpaiJ9oJ8w3AAA + ANUAAABX0TjrFws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUH + ABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5k + ZXgiOjEsImRlbHRhIjp7InRleHQiOiIsIGFuZCJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1 + dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMiJ9gJYWYQAAALEAAABXvYo6mgs6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7 + InRleHQiOiIgbGVmdCBhZ2FpbiAoIn0sInAiOiJhYmNkZWZnaGlqayJ9rw9KlgAAANgAAABXKagv + pgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNh + dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRl + bHRhIjp7InRleHQiOiJvciByaWdodCJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpB + QkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMiJ9Lnr5CwAAAKgAAABX0HrPaQs6ZXZlbnQtdHlw + ZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTpt + ZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQi + OiItbGVmdC1yaWdodCJ9LCJwIjoiYWJjZCJ9FH8ZQgAAALoAAABXyloLiws6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIg + aW4gY291bnRyaWVzIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdCJ9VacGFAAAAOQAAABXTXl6 + IQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNh + dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRl + bHRhIjp7InRleHQiOiIgd2hlcmUgdHJhZmZpYyBkcml2ZXMifSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMSJ9CMzkoQAAALQAAABXdWq1 + 6gs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNh + dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRl + bHRhIjp7InRleHQiOiIgb24gdGhlIGxlZnQifSwicCI6ImFiY2RlZmdoaWprbG1ubyJ9B/NSNAAA + AMcAAABXyxgv9Qs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUH + ABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5k + ZXgiOjEsImRlbHRhIjp7InRleHQiOiIsIGxpa2UgdGhlIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9w + cXJzdHV2d3h5ekFCQ0RFRkdISUoifX377ikAAACpAAAAV+0a5tkLOmV2ZW50LXR5cGUHABFjb250 + ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10 + eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIFVLKS4g + IFxuIn0sInAiOiJhYmNkZWZnIn00v7bZAAAA2QAAAFcUyAYWCzpldmVudC10eXBlBwARY29udGVu + dEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlw + ZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiAgIC0gTGlz + dGVuIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNU + VVZXWFlaMCJ92B4KIgAAAMsAAABXDujC9As6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgZm9yIGFwcHJvYWNoaW5nIn0s + InAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdIIn1u7pLHAAAAugAAAFfKWguL + CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0 + aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVs + dGEiOnsidGV4dCI6IiB2ZWhpY2xlcywifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3In0O + +rRAAAAA5wAAAFcK2QDxCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQt + dHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50Qmxv + Y2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBlc3BlY2lhbGx5IGJpa2VzIn0sInAiOiJhYmNk + ZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1Njc4 + In2NVYNwAAAApAAAAFcViiJoCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRl + bnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50 + QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBvciBxdWlldCJ9LCJwIjoiYWIife8s2uEA + AAC/AAAAVwK6hPsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIGVsZWN0cmljIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9w + cXJzdHV2d3h5ekFCQyJ9bnx5rgAAAM8AAABX+2hkNAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9j + a0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVl + dmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgY2Fycy5cblxuIn0s + InAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUiJ9PvgksQAA + ALYAAABXD6rmigs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUH + ABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5k + ZXgiOjEsImRlbHRhIjp7InRleHQiOiI0LiAqKiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1 + dnd4In17T+dkAAAAxgAAAFf2eAZFCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNv + bnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250 + ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IkVuc3VyZSBBbGwifSwicCI6ImFiY2Rl + ZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJIn0R/Vc+AAAAswAAAFfHSmn6CzpldmVudC10 + eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N + Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4 + dCI6IiBUcmFmZmljIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXIifb7gho4AAACrAAAAV5fatbkL + OmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRp + b24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0 + YSI6eyJ0ZXh0IjoiIEhhcyJ9LCJwIjoiYWJjZGVmZ2hpamtsbW4ifUoqnzEAAACoAAAAV9B6z2kL + OmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRp + b24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0 + YSI6eyJ0ZXh0IjoiIFN0b3BwZWQqKjoifSwicCI6ImFiY2QifSpv9C4AAACqAAAAV6q6nAkLOmV2 + ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24v + anNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6 + eyJ0ZXh0IjoiICBcbiAgIn0sInAiOiJhYmNkZWZnaGlqayJ9DkO2lQAAAKoAAABXqrqcCQs6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7 + InRleHQiOiIgLSBNYWtlIn0sInAiOiJhYmNkZWZnaGlqIn1//CRBAAAA4AAAAFe4+dzhCzpldmVu + dC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pz + b24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsi + dGV4dCI6IiBleWUgY29udGFjdCB3aXRoIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5 + ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEifSpeiO4AAADoAAAAV4iJlyALOmV2ZW50LXR5 + cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06 + bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0 + IjoiIGRyaXZlcnMgaWYgcG9zc2libGUifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6 + QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIzNDU2In2zxrgFAAAApQAAAFco6gvYCzpldmVu + dC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pz + b24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsi + dGV4dCI6IiwifSwicCI6ImFiY2RlZmdoaWprIn264dm0AAAAywAAAFcO6ML0CzpldmVudC10eXBl + BwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1l + c3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6 + IiBhbmQifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFS + U1QifddJ1A0AAADSAAAAV2MYNwcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29u + dGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRl + bnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIHdhaXQifSwicCI6ImFiY2RlZmdoaWpr + bG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVoifXPViOMAAADLAAAAVw7o + wvQLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGlj + YXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJk + ZWx0YSI6eyJ0ZXh0IjoiIGZvciB2ZWhpY2xlcyJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1 + dnd4eXpBQkNERUZHSElKSyJ9ins30wAAANUAAABX0TjrFws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgdG8gY29tZSJ9 + LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZ + WiJ9y6hJIAAAAKMAAABXp6r+eAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250 + ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVu + dEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgdG8gYSJ9LCJwIjoiYWJjZGUifUYUV14A + AADmAAAAVze5KUELOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIGNvbXBsZXRlIHN0b3AgYmVmb3JlIn0sInAiOiJhYmNk + ZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMyJ9W8kh + JQAAAMAAAABXeTjz5Qs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5 + cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2Nr + SW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgc3RlcHBpbmcifSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3eHl6QUJDRCJ9HzF1CwAAAKcAAABXUipYuAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgaW50byJ9LCJw + IjoiYWJjZGVmZ2hpIn0rCPpBAAAApwAAAFdSKli4CzpldmVudC10eXBlBwARY29udGVudEJsb2Nr + RGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2 + ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiB0aGUgcm9hZCJ9LCJw + IjoiYWJjZGUifUNfI9IAAADVAAAAV9E46xcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0 + YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7 + ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiLiJ9LCJwIjoiYWJjZGVmZ2hp + amtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NTYifZl574gA + AADMAAAAV7zIHuQLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiICBcbiAgIC0ifSwicCI6ImFiY2RlZmdoaWprbG1ub3Bx + cnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFEifde9ba0AAADHAAAAV8sYL/ULOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0Ijoi + IFdhdGNoIGZvciB0dXJuaW5nIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCIn37 + ylqNAAAAwwAAAFc+mIk1CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQt + dHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50Qmxv + Y2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiB2ZWhpY2xlcywifSwicCI6ImFiY2RlZmdoaWpr + bG1ub3BxcnN0dXZ3eHl6QUJDREVGIn09DBSBAAAAyAAAAFdJSLgkCzpldmVudC10eXBlBwARY29u + dGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2Ut + dHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBldmVu + IGlmIHlvdSJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSEkifacyI5kA + AACtAAAAVxiaQBkLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIGhhdmUgdGhlIHJpZ2h0In0sInAiOiJhYmNkZSJ9JpOe + oQAAAL4AAABXP9qtSws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5 + cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2Nr + SW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgb2YifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0 + dXZ3eHl6QUJDREVGR0gifbKKBZYAAADQAAAAVxnYZGcLOmV2ZW50LXR5cGUHABFjb250ZW50Qmxv + Y2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAF + ZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIHdheS5cblxuIn0s + InAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUIn2RnRbp + AAAAwQAAAFdEWNpVCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlw + ZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJ + bmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IjUuICoqIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJz + dHV2d3h5ekFCQ0RFRkdISSJ9gPxh7AAAAM4AAABXxghNhAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiJDcm9zcyBQcm9t + cHQifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PIn3keRBO + AAAAzgAAAFfGCE2ECzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlw + ZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJ + bmRleCI6MSwiZGVsdGEiOnsidGV4dCI6Imx5IGFuZCJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFy + c3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFUifef2YhIAAAC+AAAAVz/arUsLOmV2ZW50LXR5 + cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06 + bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0 + IjoiIFNhZiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHIn1tku/OAAAA + zgAAAFfGCE2ECzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcA + EGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRl + eCI6MSwiZGVsdGEiOnsidGV4dCI6ImVseSoqOiAgXG4ifSwicCI6ImFiY2RlZmdoaWprbG1ub3Bx + cnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFEifTY9+V0AAADNAAAAV4GoN1QLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0Ijoi + ICAgLSBXYWxrIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1O + T1BRIn1uCkI4AAAA0AAAAFcZ2GRnCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNv + bnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250 + ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBzdHJhaWdodCBhY3Jvc3MifSwicCI6 + ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTSJ9gVs2OQAAAMEAAABXRFja + VQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNh + dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRl + bHRhIjp7InRleHQiOiLigJQifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVG + R0hJSksifX9jS68AAAC4AAAAV7CaWOsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06 + Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNv + bnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiZG9u4oCZdCJ9LCJwIjoiYWJjZGVm + Z2hpamtsbW5vcHFyc3R1dnd4In3BcW0eAAAA0wAAAFdeeB63CzpldmVudC10eXBlBwARY29udGVu + dEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlw + ZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBydW4gb3Ii + fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldY + WSJ92fIbnAAAALMAAABXx0pp+gs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250 + ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVu + dEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgc3RvcCJ9LCJwIjoiYWJjZGVmZ2hpamts + bW5vcHFyc3R1In0q4uDsAAAAsgAAAFf6KkBKCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVs + dGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50 + eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBtaWR3YXkifSwicCI6ImFi + Y2RlZmdoaWprbG1ub3BxciJ9ogKTGQAAANoAAABXU2h8xgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIuICBcbiAgIn0s + InAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFla + MDEyMzQ1In2YF3jzAAAAtQAAAFdICpxaCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGEN + OmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJj + b250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiAtIFN0YXkgaW5zaWRlIn0sInAi + OiJhYmNkZWZnaGlqa2xtbiJ90ahl1AAAAMAAAABXeTjz5Qs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgY3Jvc3MifSwi + cCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGRyJ9Ji6+hgAAAKYAAABXb0pxCAs6 + ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv + bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRh + Ijp7InRleHQiOiJ3YWxrIn0sInAiOiJhYmNkZWZnaGkifV+az4EAAACmAAAAV29KcQgLOmV2ZW50 + LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNv + bg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0 + ZXh0IjoiIGxpbmVzIn0sInAiOiJhYmNkZWZnIn2/7zd5AAAAygAAAFcziOtECzpldmVudC10eXBl + BwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1l + c3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6 + IiBpZiB0aGV5In0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1O + TyJ9hxAIoAAAAMkAAABXdCiRlAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250 + ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVu + dEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiLigJlyZSBwcmVzZW50In0sInAiOiJhYmNk + ZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISSJ9n+M4FQAAAMcAAABXyxgv9Qs6ZXZlbnQt + dHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29u + DTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRl + eHQiOiIuXG5cbjYifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktM + TU4ifY4qZc4AAADFAAAAV7HYfJULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29u + dGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRl + bnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiLiAqKlN0YXkifSwicCI6ImFiY2RlZmdo + aWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSiJ9Rz0rSgAAALEAAABXvYo6mgs6ZXZlbnQtdHlw + ZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTpt + ZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQi + OiIgQWxlcnQgVW50aWwifSwicCI6ImFiY2RlZmdoaWprbCJ9FznXYgAAALkAAABXjfpxWws6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7 + InRleHQiOiIgWW91In0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCIn24MB6IAAAA + xgAAAFf2eAZFCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcA + EGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRl + eCI6MSwiZGVsdGEiOnsidGV4dCI6IiBSZWFjaCB0aGUgT3RoZXIifSwicCI6ImFiY2RlZmdoaWpr + bG1ub3BxcnN0dXZ3eHl6QUJDIn338j1vAAAA3gAAAFem6NoGCzpldmVudC10eXBlBwARY29udGVu + dEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlw + ZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBTaWRlKio6 + ICBcbiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT + VFVWV1hZWjAxMjM0In0dF07bAAAAxwAAAFfLGC/1CzpldmVudC10eXBlBwARY29udGVudEJsb2Nr + RGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2 + ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiAgIC0ifSwicCI6ImFi + Y2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUCJ9Am5r2gAAAMQAAABXjLhV + JQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNh + dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRl + bHRhIjp7InRleHQiOiIgS2VlcCBzY2FubmluZyJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1 + dnd4eXpBQkMifcbX8ccAAACwAAAAV4DqEyoLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0 + YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7 + ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIGZvciB0cmFmZmljIGFzIn0s + InAiOiJhYmNkZWZnaCJ9e5aFbAAAANUAAABX0TjrFws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9j + a0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVl + dmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgeW91IGNyb3NzIn0s + InAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWCJ9 + /zAK0wAAALoAAABXyloLiws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50 + LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJs + b2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIuIEF2b2lkIn0sInAiOiJhYmNkZWZnaGlqa2xt + bm9wcXJzdHV2d3h5eiJ9eBlaFAAAAOcAAABXCtkA8Qs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9j + a0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVl + dmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgZGlzdHJhY3Rpb25z + IGxpa2UgcGhvbmVzIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpL + TE1OT1BRUlNUVVZXWFlaMCJ9axpwEAAAAMsAAABXDujC9As6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgb3IgaGVhZHBo + b25lcy5cblxuIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFIn29O66RAAAA + vgAAAFc/2q1LCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcA + EGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRl + eCI6MSwiZGVsdGEiOnsidGV4dCI6Ii0tLVxuXG4ifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0 + dXZ3eHl6QUJDRCJ9cUSyiwAAAOQAAABXTXl6IQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0Rl + bHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVu + dHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIjIyMgKipBZGRpdGlvbmFs + In0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZX + WFlaMDEyMzQ1NiJ9Z9OJJwAAALUAAABXSAqcWgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0Rl + bHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVu + dHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgVGlwcyoqIn0sInAiOiJh + YmNkZWZnaGlqa2xtbm9wcXJzdHUifeMvWxYAAACjAAAAV6eq/ngLOmV2ZW50LXR5cGUHABFjb250 + ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10 + eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiICBcbi0g + KioifSwicCI6ImFiIn2gtBjDAAAAzwAAAFf7aGQ0CzpldmVudC10eXBlBwARY29udGVudEJsb2Nr + RGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2 + ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IkF0In0sInAiOiJhYmNk + ZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaIn3qgc0dAAAA + xQAAAFex2HyVCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcA + EGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRl + eCI6MSwiZGVsdGEiOnsidGV4dCI6IiBOaWdodCoqOiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFy + c3R1dnd4eXpBQkNERUZHSEkifaFIv0wAAADeAAAAV6bo2gYLOmV2ZW50LXR5cGUHABFjb250ZW50 + QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBl + BwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIFdlYXIgcmVm + bGVjdGl2ZSJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9Q + UVJTVFVWV1hZWjAifam7ALwAAADFAAAAV7HYfJULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tE + ZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZl + bnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIGNsb3RoaW5nIG9yIGNh + cnJ5In0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5eiJ9fsi9PAAAAMYAAABX9ngGRQs6 + ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv + bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRh + Ijp7InRleHQiOiIgYSBmbGFzaGxpZ2h0In0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5 + ekFCQ0RFRiJ9eUZ9jQAAAMwAAABXvMge5As6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgdG8gaW1wcm92ZSJ9LCJwIjoi + YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTiJ9JAPw3wAAAM0AAABXgag3 + VAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNh + dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRl + bHRhIjp7InRleHQiOiIgdmlzaWJpbGl0eS4gIFxuIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJz + dHV2d3h5ekFCQ0RFRkdISUoifWm9y0AAAACmAAAAV29KcQgLOmV2ZW50LXR5cGUHABFjb250ZW50 + QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBl + BwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiLSAqKldpdGgi + fSwicCI6ImFiY2RlIn12nPk7AAAAuQAAAFeN+nFbCzpldmVudC10eXBlBwARY29udGVudEJsb2Nr + RGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2 + ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBLaWRzIn0sInAiOiJh + YmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekEifbvPJckAAAC6AAAAV8paC4sLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0Ijoi + IG9yIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0QifT7Asj0AAADQAAAAVxnY + ZGcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGlj + YXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJk + ZWx0YSI6eyJ0ZXh0IjoiIERpc2FiaWxpdGllcyoqOiBIb2xkIn0sInAiOiJhYmNkZWZnaGlqa2xt + bm9wcXJzdHV2d3h5ekFCQ0RFRkdIIn2zf6F3AAAA2wAAAFduCFV2CzpldmVudC10eXBlBwARY29u + dGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2Ut + dHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBoYW5k + cyB3aXRoIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BR + UlNUVVZXWFlaMDEyIn3F8vnVAAAA0wAAAFdeeB63CzpldmVudC10eXBlBwARY29udGVudEJsb2Nr + RGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2 + ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBjaGlsZHJlbiwifSwi + cCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVViJ9Xt6E + +wAAALcAAABXMsrPOgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5 + cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2Nr + SW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgYW5kIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJz + dHV2d3h5eiJ9uU0ouAAAAK8AAABXYloTeQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgdXNlIGFzc2lzdGl2ZSJ9LCJw + IjoiYWJjZGVmZ2gifSslP1YAAADMAAAAV7zIHuQLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tE + ZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZl + bnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIGRldmljZXMifSwicCI6 + ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFEifcrsoFMAAADFAAAA + V7HYfJULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBw + bGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4Ijox + LCJkZWx0YSI6eyJ0ZXh0IjoiIChlLmcifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6 + QUJDREVGR0hJSktMTSJ9nOWytgAAAMgAAABXSUi4JAs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9j + a0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVl + dmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIuLCB3aGl0ZSJ9LCJw + IjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNIn0HujirAAAA1AAAAFfs + WMKnCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxp + Y2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwi + ZGVsdGEiOnsidGV4dCI6IiBjYW5lcykuIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5 + ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFkifXWVAY4AAACgAAAAV+AKhKgLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0Ijoi + IFNlZWsifSwicCI6ImFiIn1PUExjAAAAswAAAFfHSmn6CzpldmVudC10eXBlBwARY29udGVudEJs + b2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcA + BWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBwZWRlc3RyaWFu + IGJyaWRnZXMifSwicCI6ImFiY2RlZmcifcY0oMMAAACsAAAAVyX6aakLOmV2ZW50LXR5cGUHABFj + b250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2Fn + ZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIG9y + IHVuZGVyIn0sInAiOiJhYmNkZWZnaGlqIn3JxBMsAAAA0gAAAFdjGDcHCzpldmVudC10eXBlBwAR + Y29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3Nh + Z2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6InBh + c3NlcyBpZiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9Q + UVJTVFVWIn2Cl3H2AAAAxwAAAFfLGC/1CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGEN + OmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJj + b250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBhdmFpbGFibGUuICBcbiJ9LCJw + IjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERSJ9kcRIYAAAAMkAAABXdCiRlAs6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7 + InRleHQiOiItICoqVW4ifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJ + SktMTU5PUCJ9XJqIlwAAANAAAABXGdhkZws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRh + DTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsi + Y29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiJtYXJrZWQgUm9hZHMifSwicCI6 + ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFEifTHL6pYAAAC6AAAA + V8paC4sLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBw + bGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4Ijox + LCJkZWx0YSI6eyJ0ZXh0IjoiKio6IENyb3NzIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 + d3gifRuP2FMAAADDAAAAVz6YiTULOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29u + dGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRl + bnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIHdoZXJlIn0sInAiOiJhYmNkZWZnaGlq + a2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUoifWDtrskAAADWAAAAV5aYkccLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0Ijoi + IHlvdSJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJT + VFVWV1hZWjAxMjM0In1kEsdAAAAArQAAAFcYmkAZCzpldmVudC10eXBlBwARY29udGVudEJsb2Nr + RGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2 + ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBjYW4gc2VlIG9uIn0s + InAiOiJhYmNkZWZnaGkifTVAemEAAADOAAAAV8YITYQLOmV2ZW50LXR5cGUHABFjb250ZW50Qmxv + Y2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAF + ZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiY29taW5nIHRyYWZm + aWMgY2xlYXJseSJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERSJ9X86ExwAA + AMIAAABXA/ighQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUH + ABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5k + ZXgiOjEsImRlbHRhIjp7InRleHQiOiIsIGFuZCBuZXZlciJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5v + cHFyc3R1dnd4eXpBQkNEIn1RlAtEAAAA0AAAAFcZ2GRnCzpldmVudC10eXBlBwARY29udGVudEJs + b2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcA + BWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBhc3N1bWUgZHJp + dmVycyBzZWUifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSiJ9o23F + pwAAANUAAABX0TjrFws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5 + cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2Nr + SW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgeW91LiAgXG4ifSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWSJ9OSrB8QAAANAAAABXGdhkZws6 + ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlv + bi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRh + Ijp7InRleHQiOiItICoqIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdI + SUpLTE1OT1BRUlNUVVZXWFkifaZgaiYAAADWAAAAV5aYkccLOmV2ZW50LXR5cGUHABFjb250ZW50 + QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBl + BwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiSW50ZXJuYXRp + b25hbCBUcmF2ZWwifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktM + TU5PIn0ylrrwAAAA0QAAAFckuE3XCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNv + bnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250 + ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IioqOiBOb3RlIn0sInAiOiJhYmNkZWZn + aGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVYifTYkCvMAAADVAAAAV9E4 + 6xcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGlj + YXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJk + ZWx0YSI6eyJ0ZXh0IjoiIGxvY2FsIHRyYWZmaWMgcGF0dGVybnMifSwicCI6ImFiY2RlZmdoaWpr + bG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSksifSa9u2UAAADaAAAAV1NofMYLOmV2ZW50LXR5cGUH + ABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVz + c2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0Ijoi + IChlLmcifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFS + U1RVVldYWVowMTIzNDU2NyJ93YsIyQAAALQAAABXdWq16gs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRC + bG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUH + AAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIuLCBsZWZ0In0s + InAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdCJ9H9aKzgAAANkAAABXFMgGFgs6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIt + c2lkZSBkcml2aW5nKSJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElK + S0xNTk9QUVJTVFVWV1gife51UIUAAADLAAAAVw7owvQLOmV2ZW50LXR5cGUHABFjb250ZW50Qmxv + Y2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAF + ZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIGFuZCBwZWRlc3Ry + aWFuIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISSJ9MhOqFAAAALkA + AABXjfpxWws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBh + cHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgi + OjEsImRlbHRhIjp7InRleHQiOiIgY3VzdG9tcyJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1 + dnd4In2CR9mGAAAAsgAAAFf6KkBKCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNv + bnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250 + ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6Ii5cblxuIyMjICoqIn0sInAiOiJhYmNk + ZWZnaGlqa2xtbiJ9RTbS6AAAAMQAAABXjLhVJQs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0Rl + bHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVu + dHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiJSZW1lbWJlcioqOiJ9LCJw + IjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUYifc7Jyr0AAADWAAAAV5aYkccLOmV2 + ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24v + anNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6 + eyJ0ZXh0IjoiICBcbi0gKioifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVG + R0hJSktMTU5PUFFSU1RVVldYWVowIn1CmxbsAAAAyAAAAFdJSLgkCzpldmVudC10eXBlBwARY29u + dGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2Ut + dHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IlJpZ2h0 + In0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1AifefXqWgA + AADUAAAAV+xYwqcLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIG9mIFdheSDiiaAifSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVViJ92TQhOQAAAKcAAABXUipYuAs6ZXZl + bnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9q + c29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7 + InRleHQiOiIgSW52In0sInAiOiJhYmNkZWZnaGlqIn3gDB8IAAAAqAAAAFfQes9pCzpldmVudC10 + eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24N + Om1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4 + dCI6ImluY2liaWxpdHkqKjoifSwicCI6ImFiIn3oglGjAAAA0gAAAFdjGDcHCzpldmVudC10eXBl + BwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1l + c3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6 + IiBFdmVuIHdpdGgifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktM + TU5PUFFSU1RVIn1nZQ9kAAAA1AAAAFfsWMKnCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVs + dGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50 + eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiBhIn0sInAiOiJhYmNkZWZn + aGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQifdLM8lgA + AADfAAAAV5uI87YLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0lu + ZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIHNpZ25hbCwgZG91YmxlIn0sInAiOiJhYmNkZWZnaGlq + a2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyIn03nKLmAAAA3wAA + AFebiPO2CzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFw + cGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6 + MSwiZGVsdGEiOnsidGV4dCI6Ii1jaGVjayB0aGF0In0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJz + dHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaMDEyMzQ1NiJ9Z0JWmQAAAL0AAABXeHrX + mws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNh + dGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRl + bHRhIjp7InRleHQiOiIgY2FycyJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE + RSJ9qkHI+QAAANkAAABXFMgGFgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250 + ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVu + dEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgYXJlIHN0b3BwaW5nLiJ9LCJwIjoiYWJj + ZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1gifekEc/cAAAC9 + AAAAV3h615sLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQ + YXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4 + IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiICBcbi0gKioifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0 + dXZ3eHl6QUIifWdkfmEAAAC7AAAAV/c6IjsLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0 + YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7 + ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiRGlzdHJhY3Rpb25zIEtpbGwi + fSwicCI6ImFiY2RlZmdoaWprbG1ub3BxIn3si8izAAAAtwAAAFcyys86CzpldmVudC10eXBlBwAR + Y29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3Nh + Z2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6Iioq + OiBTdGF5In0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2In2l3HMMAAAA2AAAAFcpqC+mCzpl + dmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9u + L2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEi + OnsidGV4dCI6IiBmb2N1c2Vk4oCUIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFC + Q0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaIn2s5ExlAAAAygAAAFcziOtECzpldmVudC10eXBlBwAR + Y29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3Nh + Z2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6Im5v + IHRleHRpbmcifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTSJ9 + fC+V/QAAANoAAABXU2h8xgs6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50 + LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJs + b2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIgb3Igc2Nyb2xsaW5nIHdoaWxlIn0sInAiOiJh + YmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUIn1/0W6bAAAA4AAA + AFe4+dzhCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFw + cGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6 + MSwiZGVsdGEiOnsidGV4dCI6IiBjcm9zc2luZy4gIFxuXG4ifSwicCI6ImFiY2RlZmdoaWprbG1u + b3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVowMTIifVjBZl8AAACtAAAAVxia + QBkLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGlj + YXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJk + ZWx0YSI6eyJ0ZXh0IjoiQnkgZm9sbG93aW5nIHRoZXNlIn0sInAiOiJhYiJ9xhJvkgAAANIAAABX + Yxg3Bws6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBs + aWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEs + ImRlbHRhIjp7InRleHQiOiIgc3RlcHMsIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5 + ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWCJ9sWhCqgAAAL4AAABXP9qtSws6ZXZlbnQtdHlwZQcA + EWNvbnRlbnRCbG9ja0RlbHRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNz + YWdlLXR5cGUHAAVldmVudHsiY29udGVudEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIg + eW914oCZIn0sInAiOiJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0QifWwfK+sAAADPAAAA + V/toZDQLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBw + bGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4Ijox + LCJkZWx0YSI6eyJ0ZXh0IjoibGwgbWluaW1pemUifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0 + dXZ3eHl6QUJDREVGR0hJSktMTU5PUFEifdacqjwAAADAAAAAV3k48+ULOmV2ZW50LXR5cGUHABFj + b250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBwbGljYXRpb24vanNvbg06bWVzc2Fn + ZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4IjoxLCJkZWx0YSI6eyJ0ZXh0IjoiIHJp + c2tzIGFuZCJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkMifQDfQ70AAACpAAAA + V+0a5tkLOmV2ZW50LXR5cGUHABFjb250ZW50QmxvY2tEZWx0YQ06Y29udGVudC10eXBlBwAQYXBw + bGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7ImNvbnRlbnRCbG9ja0luZGV4Ijox + LCJkZWx0YSI6eyJ0ZXh0IjoiIGNyb3NzIn0sInAiOiJhYmNkZWZnaGlqIn1MeGeaAAAAvQAAAFd4 + etebCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxp + Y2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwi + ZGVsdGEiOnsidGV4dCI6IiBzYWZlbHkifSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6 + QUJDIn1C4jxHAAAAqQAAAFftGubZCzpldmVudC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNv + bnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250 + ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6IiEifSwicCI6ImFiY2RlZmdoaWprbG1u + byJ9ifQ4ZwAAAMsAAABXDujC9As6ZXZlbnQtdHlwZQcAEWNvbnRlbnRCbG9ja0RlbHRhDTpjb250 + ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdlLXR5cGUHAAVldmVudHsiY29udGVu + dEJsb2NrSW5kZXgiOjEsImRlbHRhIjp7InRleHQiOiIg8J+atiJ9LCJwIjoiYWJjZGVmZ2hpamts + bW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTIn28koU8AAAAqwAAAFeX2rW5CzpldmVu + dC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pz + b24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsi + dGV4dCI6IuKZgiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vIn27RPkvAAAApQAAAFco6gvYCzpldmVu + dC10eXBlBwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pz + b24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsi + dGV4dCI6Iu+4j/CfmqYifSwicCI6ImFiY2RlIn1fGGVkAAAAxAAAAFeMuFUlCzpldmVudC10eXBl + BwARY29udGVudEJsb2NrRGVsdGENOmNvbnRlbnQtdHlwZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1l + c3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJbmRleCI6MSwiZGVsdGEiOnsidGV4dCI6 + IiJ9LCJwIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUSJ90pHE + 9gAAAK8AAABWFV0j7ws6ZXZlbnQtdHlwZQcAEGNvbnRlbnRCbG9ja1N0b3ANOmNvbnRlbnQtdHlw + ZQcAEGFwcGxpY2F0aW9uL2pzb24NOm1lc3NhZ2UtdHlwZQcABWV2ZW50eyJjb250ZW50QmxvY2tJ + bmRleCI6MSwicCI6ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFEi + fSM3jgIAAACSAAAAUdKIynsLOmV2ZW50LXR5cGUHAAttZXNzYWdlU3RvcA06Y29udGVudC10eXBl + BwAQYXBwbGljYXRpb24vanNvbg06bWVzc2FnZS10eXBlBwAFZXZlbnR7InAiOiJhYmNkZWZnaGlq + a2xtbm9wcSIsInN0b3BSZWFzb24iOiJlbmRfdHVybiJ9lR4ZiwAAAOwAAABOGWKZIAs6ZXZlbnQt + dHlwZQcACG1ldGFkYXRhDTpjb250ZW50LXR5cGUHABBhcHBsaWNhdGlvbi9qc29uDTptZXNzYWdl + LXR5cGUHAAVldmVudHsibWV0cmljcyI6eyJsYXRlbmN5TXMiOjIyMTgwfSwicCI6ImFiY2RlZmdo + aWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMIiwidXNhZ2UiOnsiaW5wdXRUb2tlbnMiOjEy + LCJvdXRwdXRUb2tlbnMiOjEyMDEsInRvdGFsVG9rZW5zIjoxMjEzfX3uDo9k + headers: + connection: + - keep-alive + content-type: + - application/vnd.amazon.eventstream + transfer-encoding: + - chunked + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_cohere/test_cohere_model_thinking_part.yaml b/tests/models/cassettes/test_cohere/test_cohere_model_thinking_part.yaml new file mode 100644 index 000000000..42ab722be --- /dev/null +++ b/tests/models/cassettes/test_cohere/test_cohere_model_thinking_part.yaml @@ -0,0 +1,290 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '150' + content-type: + - application/json + host: + - api.openai.com + method: POST + parsed_body: + input: + - content: How do I cross the street? + role: user + model: o3-mini + reasoning: + effort: high + summary: detailed + stream: false + uri: https://api.openai.com/v1/responses + response: + headers: + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '6076' + content-type: + - application/json + openai-organization: + - pydantic-28gund + openai-processing-ms: + - '21876' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + created_at: 1745304052 + error: null + id: resp_680739f4ad748191bd11096967c37c8b048efc3f8b2a068e + incomplete_details: null + instructions: null + max_output_tokens: null + metadata: {} + model: o3-mini-2025-01-31 + object: response + output: + - id: rs_680739fcbe148191ab03787b75642840048efc3f8b2a068e + summary: + - text: |- + **Understanding street crossing instructions** + + The user wants to know how to cross the street, which seems straightforward but could be ambiguous. I see this as a request for safety instructions regarding vehicular crossing. It's essential to provide safe and clear advice but also to clarify that this is informational and not legal advice. I need to remind the user to follow local road codes as well. I want to ensure I help while being careful in my wording. + type: summary_text + - text: |- + **Providing street crossing guidance** + + It seems the user's question about crossing the street could involve personal safety instructions, so I need to be careful with my response. I can offer step-by-step advice: First, look for traffic before stepping off the curb, then check left, right, and left again. If at a crosswalk, use signals and wait for a gap in traffic. It's crucial I clarify that I'm not a substitute for professional advice and to always follow local traffic laws for safety. + type: summary_text + - text: |- + **Providing safe street crossing instructions** + + I want to emphasize the importance of using crosswalks whenever possible and being extremely cautious of traffic. Distractions, like mobile phones, can make crossing dangerous, so staying alert is essential. It's crucial to obey traffic signals, especially because rules can differ in various countries. I'll share step-by-step safe crossing instructions, beginning with finding a designated crossing point and waiting for signals. Each step will stress remaining vigilant while crossing and using caution to ensure safety. Finally, I'll clarify that these are general guidelines and I'm not a safety expert. + type: summary_text + - text: |- + **Giving street crossing advice** + + When crossing the street, I advise waiting for a pedestrian signal if there is one to ensure safety. If there isn't a signal, it's crucial to look left, right, and then left again to check for oncoming traffic. Cross quickly while staying aware of potential hazards. Always be cautious, even with a signal, as vehicles may turn or not yield correctly. Avoid distractions like mobile phones during this process. Lastly, I should remind the user to check local traffic laws, as I'm not an expert. + type: summary_text + type: reasoning + - content: + - annotations: [] + text: |- + Here are some general guidelines to help you cross the street safely. Please note that these are general tips and might need to be adapted based on your surroundings, local traffic laws, and conditions: + + 1. Before you approach the street, find a safe place to cross. Whenever possible, use a designated crosswalk, pedestrian crossing, or an intersection with traffic signals. + + 2. If there's a pedestrian signal (a "walk" sign), wait for it to indicate that it's your turn to cross. Even when the signal shows it's safe, always stay alert for any vehicles that might not yet have stopped. + + 3. Stand at the curb and face traffic. This allows you to see oncoming vehicles and make eye contact with drivers when possible. + + 4. Look both ways: + • First, look to your left. + • Then, look to your right. + • Look left again before stepping off the curb. + This helps ensure you catch vehicles approaching from either direction, especially in countries where traffic drives on the right. (In countries where traffic drives on the left, simply reverse the order accordingly.) + + 5. Make sure there's a sufficient gap between vehicles before you start crossing. Even if you feel safe, take a moment to confirm that arriving vehicles are far enough away or are stopping. + + 6. Continue looking for oncoming traffic as you cross. Even if you're in the crosswalk, drivers may not always see you or might be turning unexpectedly. + + 7. Avoid distractions like using your phone or wearing headphones at a high volume. Being fully alert can make a big difference in your safety. + + 8. Walk at a steady pace—you don't need to run, but don't dawdle either. Keeping a consistent pace helps drivers predict your movement. + + Remember that local road rules and conditions can vary. In some areas, there may be additional safety measures (like pedestrian islands or flashing beacons) that you should take advantage of when crossing. If you're unsure about any specific local guidelines, it might be a good idea to check with local traffic authorities or community resources for further advice. + + Stay safe and always be aware of your surroundings when crossing any street! + type: output_text + id: msg_68073a09486c8191860c5516e97332d7048efc3f8b2a068e + role: assistant + status: completed + type: message + parallel_tool_calls: true + previous_response_id: null + reasoning: + effort: high + summary: detailed + service_tier: default + status: completed + store: true + temperature: 1.0 + text: + format: + type: text + tool_choice: auto + tools: [] + top_p: 1.0 + truncation: disabled + usage: + input_tokens: 13 + input_tokens_details: + cached_tokens: 0 + output_tokens: 1909 + output_tokens_details: + reasoning_tokens: 1472 + total_tokens: 1922 + user: null + status: + code: 200 + message: OK +- request: + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '4740' + content-type: + - application/json + host: + - api.cohere.com + method: POST + parsed_body: + messages: + - content: How do I cross the street? + role: user + - content: + - text: |- + Here are some general guidelines to help you cross the street safely. Please note that these are general tips and might need to be adapted based on your surroundings, local traffic laws, and conditions: + + 1. Before you approach the street, find a safe place to cross. Whenever possible, use a designated crosswalk, pedestrian crossing, or an intersection with traffic signals. + + 2. If there's a pedestrian signal (a "walk" sign), wait for it to indicate that it's your turn to cross. Even when the signal shows it's safe, always stay alert for any vehicles that might not yet have stopped. + + 3. Stand at the curb and face traffic. This allows you to see oncoming vehicles and make eye contact with drivers when possible. + + 4. Look both ways: + • First, look to your left. + • Then, look to your right. + • Look left again before stepping off the curb. + This helps ensure you catch vehicles approaching from either direction, especially in countries where traffic drives on the right. (In countries where traffic drives on the left, simply reverse the order accordingly.) + + 5. Make sure there's a sufficient gap between vehicles before you start crossing. Even if you feel safe, take a moment to confirm that arriving vehicles are far enough away or are stopping. + + 6. Continue looking for oncoming traffic as you cross. Even if you're in the crosswalk, drivers may not always see you or might be turning unexpectedly. + + 7. Avoid distractions like using your phone or wearing headphones at a high volume. Being fully alert can make a big difference in your safety. + + 8. Walk at a steady pace—you don't need to run, but don't dawdle either. Keeping a consistent pace helps drivers predict your movement. + + Remember that local road rules and conditions can vary. In some areas, there may be additional safety measures (like pedestrian islands or flashing beacons) that you should take advantage of when crossing. If you're unsure about any specific local guidelines, it might be a good idea to check with local traffic authorities or community resources for further advice. + + Stay safe and always be aware of your surroundings when crossing any street! + + + **Understanding street crossing instructions** + + The user wants to know how to cross the street, which seems straightforward but could be ambiguous. I see this as a request for safety instructions regarding vehicular crossing. It's essential to provide safe and clear advice but also to clarify that this is informational and not legal advice. I need to remind the user to follow local road codes as well. I want to ensure I help while being careful in my wording. + + + + **Providing street crossing guidance** + + It seems the user's question about crossing the street could involve personal safety instructions, so I need to be careful with my response. I can offer step-by-step advice: First, look for traffic before stepping off the curb, then check left, right, and left again. If at a crosswalk, use signals and wait for a gap in traffic. It's crucial I clarify that I'm not a substitute for professional advice and to always follow local traffic laws for safety. + + + + **Providing safe street crossing instructions** + + I want to emphasize the importance of using crosswalks whenever possible and being extremely cautious of traffic. Distractions, like mobile phones, can make crossing dangerous, so staying alert is essential. It's crucial to obey traffic signals, especially because rules can differ in various countries. I'll share step-by-step safe crossing instructions, beginning with finding a designated crossing point and waiting for signals. Each step will stress remaining vigilant while crossing and using caution to ensure safety. Finally, I'll clarify that these are general guidelines and I'm not a safety expert. + + + + **Giving street crossing advice** + + When crossing the street, I advise waiting for a pedestrian signal if there is one to ensure safety. If there isn't a signal, it's crucial to look left, right, and then left again to check for oncoming traffic. Cross quickly while staying aware of potential hazards. Always be cautious, even with a signal, as vehicles may turn or not yield correctly. Avoid distractions like mobile phones during this process. Lastly, I should remind the user to check local traffic laws, as I'm not an expert. + + type: text + role: assistant + - content: Considering the way to cross the street, analogously, how do I cross the river? + role: user + model: command-r7b-12-2024 + stream: false + uri: https://api.cohere.com/v2/chat + response: + headers: + access-control-expose-headers: + - X-Debug-Trace-ID + alt-svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + cache-control: + - no-cache, no-store, no-transform, must-revalidate, private, max-age=0 + content-type: + - application/json + expires: + - Thu, 01 Jan 1970 00:00:00 UTC + num_chars: + - '7193' + num_tokens: + - '1759' + pragma: + - no-cache + transfer-encoding: + - chunked + vary: + - Origin + parsed_body: + finish_reason: COMPLETE + id: 51cedafe-2e40-4941-ba6d-c364dbc356d3 + message: + content: + - text: |- + Crossing a river can be a different challenge compared to crossing a street, and the approach to safety and navigation will vary. Here are some considerations and steps to help you cross a river safely: + + 1. **Determine the River's Characteristics:** + - **Width and Depth:** Measure or estimate the width of the river. Very wide rivers may require a boat or bridge for safe crossing. Also, assess the depth; shallow areas might be safe to wade through, while deeper sections may require a different method. + - **Current and Flow:** Understand the river's current. Strong currents can make swimming dangerous and may carry debris. Always check the flow rate and direction before attempting to cross. + - **Hazards:** Look for potential hazards like rocks, logs, or underwater obstacles that could cause injury or damage to equipment. + + 2. **Choose a Safe Crossing Method:** + - **Fording:** If the river is shallow and the current is gentle, you might be able to ford the river. This involves walking through the water, often with the help of a sturdy stick or pole for balance and support. Always test the depth and current before attempting to ford. + - **Swimming:** Swimming across a river is a challenging and potentially dangerous option. It requires strong swimming skills, endurance, and knowledge of river currents. Always swim with a buddy and be aware of your surroundings. + - **Boat or Raft:** Using a boat, raft, or even an inflatable tube can be a safe and efficient way to cross. Ensure the boat is sturdy, properly equipped, and that you have the necessary safety gear, such as life jackets and a first-aid kit. + - **Bridge or Ferry:** If available, use a bridge or a ferry service. These are typically the safest and most reliable methods for crossing a river. + + 3. **Prepare and Pack Essential Items:** + - **Life Jacket/Personal Floatation Device (PFD):** Always wear a life jacket or PFD when crossing a river, especially if swimming or using a boat. + - **First-Aid Kit:** Carry a basic first-aid kit to handle any minor injuries that might occur during the crossing. + - **Map and Compass:** Navigate the river and its surroundings with the help of a map and compass, especially if you're in an unfamiliar area. + - **Communication Device:** Have a means of communication, such as a satellite phone or a personal locator beacon, especially in remote areas. + - **Dry Clothing and Shelter:** Pack extra dry clothing and a waterproof shelter (like a tarp or tent) in case you get wet or need to wait out bad weather. + + 4. **Follow River Safety Guidelines:** + - **Stay on Marked Paths:** If there are designated river paths or trails, use them. These routes are often designed to be safer and less prone to hazards. + - **Avoid Hazards:** Be cautious of slippery rocks, strong currents, and hidden underwater obstacles. Never swim or ford in areas with known dangers. + - **Group Safety:** If crossing with others, stay together. It's easier to keep an eye on each other and provide assistance if needed. + + 5. **Be Prepared for Emergencies:** + - **Know Emergency Procedures:** Familiarize yourself with river rescue techniques and procedures. Learn how to signal for help and basic survival skills. + - **Carry Emergency Supplies:** Pack emergency supplies, including a whistle, a bright-colored cloth to signal, and a signal mirror (if available). + - **Leave a Plan:** Inform someone on the riverbank about your crossing plans, including your expected time of return. This person can raise the alarm if you don't return as scheduled. + + Remember, crossing a river can be a challenging and potentially dangerous endeavor. Always prioritize safety, and if in doubt, seek professional guidance or assistance from experienced river guides or local authorities. It's better to be over-prepared than caught off guard in a river crossing situation. + type: text + role: assistant + usage: + billed_units: + input_tokens: 954 + output_tokens: 805 + tokens: + input_tokens: 1457 + output_tokens: 807 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_deepseek/test_deepseek_model_thinking_part.yaml b/tests/models/cassettes/test_deepseek/test_deepseek_model_thinking_part.yaml new file mode 100644 index 000000000..d1486d891 --- /dev/null +++ b/tests/models/cassettes/test_deepseek/test_deepseek_model_thinking_part.yaml @@ -0,0 +1,91 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '118' + content-type: + - application/json + host: + - api.deepseek.com + method: POST + parsed_body: + messages: + - content: How do I cross the street? + role: user + model: deepseek-reasoner + n: 1 + stream: false + uri: https://api.deepseek.com/chat/completions + response: + headers: + access-control-allow-credentials: + - 'true' + connection: + - keep-alive + content-length: + - '4148' + content-type: + - application/json + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + vary: + - origin, access-control-request-method, access-control-request-headers + parsed_body: + choices: + - finish_reason: stop + index: 0 + logprobs: null + message: + content: "Crossing the street safely involves careful observation and following traffic rules. Here's a step-by-step + guide:\n\n1. **Find a Safe Spot**: \n - Use a **crosswalk** or intersection with pedestrian signals whenever + possible. \n - Avoid crossing between parked cars, curves, or hills where visibility is poor. \n\n2. **Check + Traffic Signals**: \n - Wait for the \"walk\" signal or green light. If there's a button, press it to activate + the pedestrian signal. \n - **Never cross** on a red light, flashing \"don't walk,\" or steady hand signal. + \ \n\n3. **Look Both Ways**: \n - **Look left, right, and left again** (or right, left, right in countries + with left-side traffic). \n - Keep checking for cars, bikes, or motorcycles while crossing. \n\n4. **Make + Eye Contact**: \n - Ensure drivers see you before stepping into the road, especially at stop signs or turning + lanes. \n\n5. **Stay Focused**: \n - Avoid distractions like phones, headphones, or conversations. \n - + Walk briskly (don't run) and follow a straight path. \n\n6. **Watch for Turning Vehicles**: \n - Be cautious + of cars turning into your path, even if you have the right of way. \n\n7. **Be Visible**: \n - At night, wear + reflective clothing or use a flashlight. \n\n8. **Use Pedestrian Infrastructure**: \n - Opt for bridges, tunnels, + or islands if available. \n\n9. **Follow Local Laws**: \n - Avoid jaywalking—it's illegal in many areas and + increases accident risk. \n\n**Remember**: Never assume drivers will stop. Prioritize safety over speed, and + stay alert until you've fully crossed." + reasoning_content: |- + Okay, the user is asking how to cross the street. Let me think about how to approach this. First, I need to make sure I cover all the essential steps clearly. Maybe start with finding a safe place to cross. Crosswalks and intersections are important here. I should mention looking for traffic lights or pedestrian signals. + + Wait, what about places without crosswalks? Maybe advise them to choose a well-lit area with a clear view of traffic. Then, checking both directions for cars. But in some countries, traffic is on the left, so I should mention looking left and right, then left again, or something like that. Wait, maybe just say look both ways multiple times to be safe. + + Oh, and making eye contact with drivers if possible. That's a good point. Also, stay visible, maybe avoid distractions like phones. Don't forget to walk, not run, and keep looking while crossing. What about if there's a button to press at the crosswalk? Maybe include that step. Also, explain different signals like the walking person and the hand signal. Maybe warn against crossing on a red hand or don't walk signal. + + What about situations where there's no traffic light? Like a stop sign? The pedestrian has the right of way there, but still need to be cautious. Also, remind them to watch for turning vehicles, even if they have the right of way. Maybe add something about using pedestrian bridges or tunnels if available. Oh, and be extra careful at night or in bad weather. Wear reflective clothing if possible. + + I should structure this step by step. Start with finding a safe spot, checking signals, looking both ways, making eye contact, staying focused, walking straight across, and continuing to look. Maybe include additional tips like using pedestrian infrastructure, being cautious at night, and following local laws. Also, emphasize not assuming drivers see you. Did I miss anything? Maybe jaywalking? Advise against it. Alright, I think that covers the basics. Need to present it clearly and concisely. + role: assistant + created: 1745330951 + id: 181d9669-2b3a-445e-bd13-2ebff2c378f6 + model: deepseek-reasoner + object: chat.completion + system_fingerprint: fp_5417b77867_prod0225 + usage: + completion_tokens: 789 + completion_tokens_details: + reasoning_tokens: 415 + prompt_cache_hit_tokens: 0 + prompt_cache_miss_tokens: 12 + prompt_tokens: 12 + prompt_tokens_details: + cached_tokens: 0 + total_tokens: 801 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_gemini/test_gemini_model_thinking_part.yaml b/tests/models/cassettes/test_gemini/test_gemini_model_thinking_part.yaml new file mode 100644 index 000000000..cf90bafe0 --- /dev/null +++ b/tests/models/cassettes/test_gemini/test_gemini_model_thinking_part.yaml @@ -0,0 +1,278 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '150' + content-type: + - application/json + host: + - api.openai.com + method: POST + parsed_body: + input: + - content: How do I cross the street? + role: user + model: o3-mini + reasoning: + effort: high + summary: detailed + stream: false + uri: https://api.openai.com/v1/responses + response: + headers: + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '5163' + content-type: + - application/json + openai-organization: + - pydantic-28gund + openai-processing-ms: + - '20560' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + created_at: 1745064959 + error: null + id: resp_680393ff82488191a7d0850bf0dd99a004f0817ea037a07b + incomplete_details: null + instructions: null + max_output_tokens: null + metadata: {} + model: o3-mini-2025-01-31 + object: response + output: + - id: rs_6803940b4d188191838f9713b14072ae04f0817ea037a07b + summary: + - text: |- + **Providing street-crossing instructions** + + The user's question about crossing the street seems straightforward, but I want to ensure I provide safe instructions. It's important to adhere to safety guidelines while being clear. I need to include disclaimers about not being a substitute for professional advice or local regulations. My instructions can be general: stop, look both ways, use crosswalks, and follow traffic signals if they're available. I'll also mention that location-specific rules may apply, just to be thorough. + type: summary_text + - text: |- + **Recalling street-crossing instructions** + + I need to summarize safe street-crossing instructions, making sure to highlight key safety tips. I'll emphasize to look left, right, and then left again, and to use crosswalks where available. It's important to clarify that I'm not a city planner or a safety professional, so my guidance is general in nature. I also want to include reminders about not assuming drivers will see you, and stressing the need for caution when no crosswalks are present. + type: summary_text + - text: "**Providing safe crossing instructions**\n\nI'm preparing step-by-step instructions for crossing the street + safely, emphasizing key guidelines. I want to ensure drivers are cautious and remind everyone to avoid distractions + like phones. My steps will be clear: \n\n1. Stop at the edge of the sidewalk. \n2. Look left, right, and left + again to check for traffic. \n3. Wait for a clear gap in the traffic. \n4. Follow any pedestrian signals or + signs. \n5. Cross the street when it's safe. \n6. Stay alert for vehicles while crossing. \n\nI'll include + a disclaimer that this isn't professional advice and encourage using good judgment." + type: summary_text + type: reasoning + - content: + - annotations: [] + text: |- + Here are guidelines for safely crossing a street. Remember that these tips are general and may need to be adjusted depending on your local traffic laws and the specific situation. They are not a substitute for professional safety advice. + + 1. Before you approach the street: + • Use the sidewalk if available and get to the curb or edge of the road. + • If you're a child or feel unsure, try to have an adult accompany you. + + 2. When you're ready to cross: + • Look carefully in all directions—start by looking left, then right, and left again. In countries where you drive on the left you'll want to adjust accordingly. + • Listen for vehicles and be aware of turning cars, which might not be immediately in your line of sight. + • Make eye contact with drivers if possible so that you know they see you. + + 3. Use designated crossing areas whenever possible: + • If there's a pedestrian crosswalk, use it. Crosswalks and traffic signals are there to help manage the flow of both vehicles and pedestrians. + • If there's a "Walk" signal, wait until it's on before crossing. Even if the signal turns green for pedestrians, always take an extra moment to ensure that approaching drivers are stopping. + + 4. While crossing: + • Continue to remain alert and avoid distractions like cell phones or headphones that could prevent you from noticing approaching traffic. + • Walk at a steady pace and stay in the crosswalk until you have completely reached the other side. + + 5. After crossing: + • Once you've safely reached the other side, continue to be aware of any vehicles that might be turning or reversing. + + Always be cautious—even if you have the right-of-way—and understand that it's better to wait a moment longer than risk being caught off guard. Stay safe! + type: output_text + id: msg_68039413525c8191aca9aa8f886eaf5d04f0817ea037a07b + role: assistant + status: completed + type: message + parallel_tool_calls: true + previous_response_id: null + reasoning: + effort: high + summary: detailed + service_tier: default + status: completed + store: true + temperature: 1.0 + text: + format: + type: text + tool_choice: auto + tools: [] + top_p: 1.0 + truncation: disabled + usage: + input_tokens: 13 + input_tokens_details: + cached_tokens: 0 + output_tokens: 2028 + output_tokens_details: + reasoning_tokens: 1664 + total_tokens: 2041 + user: null + status: + code: 200 + message: OK +- request: + headers: + accept: + - '*/*' + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '3904' + content-type: + - application/json + host: + - generativelanguage.googleapis.com + method: POST + parsed_body: + contents: + - parts: + - text: How do I cross the street? + role: user + - parts: + - text: |- + **Providing street-crossing instructions** + + The user's question about crossing the street seems straightforward, but I want to ensure I provide safe instructions. It's important to adhere to safety guidelines while being clear. I need to include disclaimers about not being a substitute for professional advice or local regulations. My instructions can be general: stop, look both ways, use crosswalks, and follow traffic signals if they're available. I'll also mention that location-specific rules may apply, just to be thorough. + thought: true + - text: |- + **Recalling street-crossing instructions** + + I need to summarize safe street-crossing instructions, making sure to highlight key safety tips. I'll emphasize to look left, right, and then left again, and to use crosswalks where available. It's important to clarify that I'm not a city planner or a safety professional, so my guidance is general in nature. I also want to include reminders about not assuming drivers will see you, and stressing the need for caution when no crosswalks are present. + thought: true + - text: "**Providing safe crossing instructions**\n\nI'm preparing step-by-step instructions for crossing the street + safely, emphasizing key guidelines. I want to ensure drivers are cautious and remind everyone to avoid distractions + like phones. My steps will be clear: \n\n1. Stop at the edge of the sidewalk. \n2. Look left, right, and left + again to check for traffic. \n3. Wait for a clear gap in the traffic. \n4. Follow any pedestrian signals or + signs. \n5. Cross the street when it's safe. \n6. Stay alert for vehicles while crossing. \n\nI'll include + a disclaimer that this isn't professional advice and encourage using good judgment." + thought: true + - text: |- + Here are guidelines for safely crossing a street. Remember that these tips are general and may need to be adjusted depending on your local traffic laws and the specific situation. They are not a substitute for professional safety advice. + + 1. Before you approach the street: + • Use the sidewalk if available and get to the curb or edge of the road. + • If you're a child or feel unsure, try to have an adult accompany you. + + 2. When you're ready to cross: + • Look carefully in all directions—start by looking left, then right, and left again. In countries where you drive on the left you'll want to adjust accordingly. + • Listen for vehicles and be aware of turning cars, which might not be immediately in your line of sight. + • Make eye contact with drivers if possible so that you know they see you. + + 3. Use designated crossing areas whenever possible: + • If there's a pedestrian crosswalk, use it. Crosswalks and traffic signals are there to help manage the flow of both vehicles and pedestrians. + • If there's a "Walk" signal, wait until it's on before crossing. Even if the signal turns green for pedestrians, always take an extra moment to ensure that approaching drivers are stopping. + + 4. While crossing: + • Continue to remain alert and avoid distractions like cell phones or headphones that could prevent you from noticing approaching traffic. + • Walk at a steady pace and stay in the crosswalk until you have completely reached the other side. + + 5. After crossing: + • Once you've safely reached the other side, continue to be aware of any vehicles that might be turning or reversing. + + Always be cautious—even if you have the right-of-way—and understand that it's better to wait a moment longer than risk being caught off guard. Stay safe! + role: model + - parts: + - text: Considering the way to cross the street, analogously, how do I cross the river? + role: user + generationConfig: + thinking_config: + includeThoughts: true + thinkingBudget: 1024 + uri: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-04-17:generateContent + response: + headers: + alt-svc: + - h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 + content-length: + - '3753' + content-type: + - application/json; charset=UTF-8 + server-timing: + - gfet4t7; dur=13980 + transfer-encoding: + - chunked + vary: + - Origin + - X-Origin + - Referer + parsed_body: + candidates: + - content: + parts: + - text: |- + Okay, let's draw an analogy between crossing a street and crossing a river, applying the safety principles from the street crossing guide to the river environment. + + Think of the **river** as being like the **street** – a natural barrier you need to get across. The **hazards** on the river are different from vehicles, but they are still things that can harm you. + + Here's the analogous guide for crossing a river: + + 1. **Before you approach the river:** + * Just as you use a sidewalk to get to the street's edge, use a trail or the riverbank to get to a spot where you can assess the river. + * If you're inexperienced with rivers or unsure about the conditions, try to have someone experienced accompany you. + + 2. **When you're ready to cross:** + * Just as you look and listen for vehicles, carefully **assess the river conditions**. Look in all directions (upstream, downstream, across): + * How fast is the current moving? (Like checking vehicle speed). + * How deep does the water look? (Like judging the width and how much time you have). + * Are there obstacles in the water (rocks, logs)? (Like parked cars or road hazards). + * Is the bottom visible and does it look stable? (Like checking the road surface). + * Check upstream for potential hazards coming towards you (like debris). + * Listen to the river – the sound can tell you if the current is very strong or if there are rapids. + * Acknowledge the river's power – just as you make eye contact with drivers, respect that the river can be dangerous and doesn't care if you're trying to cross. + + 3. **Use designated crossing areas whenever possible:** + * If there's a **bridge or a ferry**, use it. These are like the crosswalks and traffic signals – the safest, established ways to cross, often managing the "flow" (of water below, or people/boats on the river). + * If you must wade or swim, look for the safest possible **crossing point** – maybe a wider, shallower section, a known ford, or a spot with a less turbulent current. This is like choosing a crosswalk instead of crossing anywhere. + + 4. **While crossing:** + * Just as you stay alert and avoid distractions, **focus completely on the crossing**. Don't be looking at your phone or distracted by conversation if you are actively navigating the water. + * Move with purpose, but carefully. If wading, maintain your balance against the current and watch your footing. If swimming, focus on your technique and direction. Stay aware of where you are relative to your intended path and the river's flow. + + 5. **After crossing:** + * Once you've safely reached the other side, take a moment to ensure you are truly out of the main flow and on stable ground. Be aware of the riverbank conditions. + + **Analogous Takeaway:** + + Just as you wouldn't just run blindly into a busy street, you shouldn't just jump into a river without understanding its conditions and choosing the safest method and location to cross. Be cautious, assess the "traffic" (current, depth, obstacles), and use the available "infrastructure" (bridges, ferries, established crossing points) whenever possible. + role: model + finishReason: STOP + index: 0 + modelVersion: gemini-2.5-flash-preview-04-17 + usageMetadata: + candidatesTokenCount: 1519 + promptTokenCount: 801 + promptTokensDetails: + - modality: TEXT + tokenCount: 801 + thoughtsTokenCount: 794 + totalTokenCount: 2320 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_groq/test_groq_model_thinking_part.yaml b/tests/models/cassettes/test_groq/test_groq_model_thinking_part.yaml new file mode 100644 index 000000000..e030025de --- /dev/null +++ b/tests/models/cassettes/test_groq/test_groq_model_thinking_part.yaml @@ -0,0 +1,345 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '219' + content-type: + - application/json + host: + - api.groq.com + method: POST + parsed_body: + messages: + - content: You are a chef. + role: system + - content: I want a recipe to cook Uruguayan alfajores. + role: user + model: deepseek-r1-distill-llama-70b + n: 1 + reasoning_format: raw + stream: false + uri: https://api.groq.com/openai/v1/chat/completions + response: + headers: + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - private, max-age=0, no-store, no-cache, must-revalidate + connection: + - keep-alive + content-length: + - '6639' + content-type: + - application/json + transfer-encoding: + - chunked + vary: + - Origin, Accept-Encoding + parsed_body: + choices: + - finish_reason: stop + index: 0 + logprobs: null + message: + content: "\nOkay, so I want to make Uruguayan alfajores. I've heard they're these delicious South American + cookies filled with dulce de leche and coated in powdered sugar. I'm not entirely sure about the exact steps, + but I'll try to figure it out.\n\nFirst, I need to gather the ingredients. The user provided a list, so I can + refer to that. It includes all-purpose flour, cornstarch, baking powder, salt, unsalted butter, powdered sugar, + eggs, vanilla extract, dulce de leche, and powdered sugar for coating. I think I have most of these in my pantry + except maybe cornstarch and dulce de leche. I'll have to make sure to get those.\n\nNow, the instructions. Preheating + the oven to 300°F (150°C) seems standard for cookies. They mentioned using a baking sheet lined with parchment + paper, so I'll prepare that. \n\nNext, making the dough. It involves mixing dry ingredients and then creaming + butter and sugar. Wait, the powdered sugar is used here, right? So I need to make sure I have enough. Then adding + the egg and vanilla. I'm a bit confused about the cornstarch part—do I mix it with the flour before adding to + the wet ingredients? I think that's what the user meant. So, the dry ingredients are flour, cornstarch, baking + powder, and salt. I should whisk those together first.\n\nOnce the dough comes together, I need to wrap it and + let it rest. Maybe 30 minutes is enough. Then, rolling it out to about 1/4 inch thickness. I'm not sure if that's + too thick or thin. I'll try to roll it evenly. Cutting into circles, probably using a cookie cutter or a glass. + The user mentioned a 2-inch diameter, so I'll aim for that.\n\nBaking for 15-20 minutes until the edges are lightly + golden. I should keep an eye on them to prevent burning. Letting them cool on the sheet for 5 minutes before moving + to a wire rack to cool completely. That makes sense because cookies can break if moved too soon.\n\nAssembling + the alfajores: spreading dulce de leche on one half and sandwiching. I'm a bit worried about handling the cookies; + they might be fragile. I'll be gentle. Then coating in powdered sugar. Maybe I should do this after they're filled + to ensure the sugar sticks properly.\n\nWait, the user mentioned two options for coating: either just powdered + sugar or a chocolate coating. I think I'll stick to the traditional powdered sugar for now. Maybe next time I + can try the chocolate version.\n\nI'm a bit concerned about the dulce de leche. If I can't find it in stores, + I might have to make it myself. The user provided a method for that, which is good. Heating condensed milk until + it thickens. I should be careful with that because it can burn easily.\n\nAlso, when forming the dough, if it's + too sticky, I might need to add a bit more flour, but I shouldn't overdo it. Maybe the cornstarch helps with the + texture. I'm not sure how the cornstarch affects the cookies—maybe it makes them lighter or crisper.\n\nI should + also make sure the butter is softened to room temperature to cream it properly with the powdered sugar. If the + butter is too hard, the mixture might not come together smoothly.\n\nAnother thing is the baking time. Since the + oven is at a lower temperature, the cookies might take a bit longer. I'll check them after 15 minutes and maybe + extend if needed. They shouldn't be too dark around the edges.\n\nWhen cooling, it's important they are completely + cool before handling, otherwise, they might break when trying to sandwich them. I'll let them sit on the rack + for at least 30 minutes.\n\nI'm thinking about how to store them. The user mentioned an airtight container at + room temperature for up to a week. Maybe I can freeze some if I don't plan to eat them all soon.\n\nI'm a bit + nervous about the assembly. The dulce de leche can be messy. I'll make sure to have a plate or tray ready to place + the assembled cookies before coating them in powdered sugar.\n\nOverall, it seems manageable. I'll take it step + by step, follow the measurements closely, and taste as I go. If something doesn't feel right, I'll adjust. I'm + excited to try these Uruguayan alfajores!\n\n\nTo make Uruguayan alfajores, follow these organized steps + for a delightful baking experience:\n\n### Ingredients:\n- 2 cups all-purpose flour\n- 1 cup cornstarch\n- 1 tsp + baking powder\n- 1/2 tsp salt\n- 1 cup unsalted butter, softened\n- 1 cup powdered sugar\n- 1 egg\n- 1 tsp vanilla + extract\n- Dulce de leche (store-bought or homemade)\n- Powdered sugar for coating\n\n### Instructions:\n\n1. + **Preheat Oven:**\n - Preheat your oven to 300°F (150°C). Line a baking sheet with parchment paper.\n\n2. **Prepare + Dough:**\n - In a bowl, whisk together flour, cornstarch, baking powder, and salt.\n - In another bowl, cream + butter and powdered sugar until smooth. Add egg and vanilla, mixing well.\n - Gradually incorporate the dry + ingredients into the wet mixture until a dough forms. Wrap and let rest for 30 minutes.\n\n3. **Roll and Cut:**\n + \ - Roll dough to 1/4 inch thickness. Cut into 2-inch circles using a cutter or glass.\n\n4. **Bake:**\n - + Place cookies on the prepared baking sheet, bake for 15-20 minutes until edges are lightly golden. Cool on the + sheet for 5 minutes, then transfer to a wire rack to cool completely.\n\n5. **Assemble Alfajores:**\n - Spread + a layer of dulce de leche on one cookie half. Sandwich with another cookie. Handle gently to avoid breaking.\n\n6. + **Coat with Powdered Sugar:**\n - Roll each alfajor in powdered sugar, pressing gently to adhere.\n\n7. **Optional + Chocolate Coating:**\n - For a chocolate version, melt chocolate and dip alfajores, then chill to set.\n\n8. + **Storage:**\n - Store in an airtight container at room temperature for up to a week. Freeze for longer storage.\n\n### + Tips:\n- Ensure butter is softened for smooth creaming.\n- Check cookies after 15 minutes to avoid over-browning.\n- + Allow cookies to cool completely before handling.\n- Homemade dulce de leche can be made by heating condensed + milk until thickened.\n\nEnjoy your traditional Uruguayan alfajores with a cup of coffee or tea!" + role: assistant + created: 1745064185 + id: chatcmpl-9748c1af-1065-410a-969a-d7fb48039fbb + model: deepseek-r1-distill-llama-70b + object: chat.completion + system_fingerprint: fp_454c494f52 + usage: + completion_time: 5.141818182 + completion_tokens: 1414 + prompt_time: 0.00448192 + prompt_tokens: 21 + queue_time: 0.086872184 + total_time: 5.146300102 + total_tokens: 1435 + usage_breakdown: + models: null + x_groq: + id: req_01js6ywkh6e62vxj89vrs19wpn + status: + code: 200 + message: OK +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '2333' + content-type: + - application/json + cookie: + - __cf_bm=8pcJXf3Ub9vLuMV_UKGfpaNNmqKlFWWsKoRxh_beZt4-1745064190-1.0.1.1-UjG7Yf6THFmT2XO7TCCBqim8hVwv2b2T0DBzEUr7ybE1tga1y_9tH3BOhsAhbFhHvCc8iHZoTLwTEDERDaEvfG54.LPb3iXdOxTIoAsgWRQ + host: + - api.groq.com + method: POST + parsed_body: + messages: + - content: You are a chef. + role: system + - content: I want a recipe to cook Uruguayan alfajores. + role: user + - content: |2- + + + To make Uruguayan alfajores, follow these organized steps for a delightful baking experience: + + ### Ingredients: + - 2 cups all-purpose flour + - 1 cup cornstarch + - 1 tsp baking powder + - 1/2 tsp salt + - 1 cup unsalted butter, softened + - 1 cup powdered sugar + - 1 egg + - 1 tsp vanilla extract + - Dulce de leche (store-bought or homemade) + - Powdered sugar for coating + + ### Instructions: + + 1. **Preheat Oven:** + - Preheat your oven to 300°F (150°C). Line a baking sheet with parchment paper. + + 2. **Prepare Dough:** + - In a bowl, whisk together flour, cornstarch, baking powder, and salt. + - In another bowl, cream butter and powdered sugar until smooth. Add egg and vanilla, mixing well. + - Gradually incorporate the dry ingredients into the wet mixture until a dough forms. Wrap and let rest for 30 minutes. + + 3. **Roll and Cut:** + - Roll dough to 1/4 inch thickness. Cut into 2-inch circles using a cutter or glass. + + 4. **Bake:** + - Place cookies on the prepared baking sheet, bake for 15-20 minutes until edges are lightly golden. Cool on the sheet for 5 minutes, then transfer to a wire rack to cool completely. + + 5. **Assemble Alfajores:** + - Spread a layer of dulce de leche on one cookie half. Sandwich with another cookie. Handle gently to avoid breaking. + + 6. **Coat with Powdered Sugar:** + - Roll each alfajor in powdered sugar, pressing gently to adhere. + + 7. **Optional Chocolate Coating:** + - For a chocolate version, melt chocolate and dip alfajores, then chill to set. + + 8. **Storage:** + - Store in an airtight container at room temperature for up to a week. Freeze for longer storage. + + ### Tips: + - Ensure butter is softened for smooth creaming. + - Check cookies after 15 minutes to avoid over-browning. + - Allow cookies to cool completely before handling. + - Homemade dulce de leche can be made by heating condensed milk until thickened. + + Enjoy your traditional Uruguayan alfajores with a cup of coffee or tea! + role: assistant + - content: Considering the Uruguayan recipe, how can I cook the Argentinian one? + role: user + model: deepseek-r1-distill-llama-70b + n: 1 + reasoning_format: parsed + stream: false + uri: https://api.groq.com/openai/v1/chat/completions + response: + headers: + alt-svc: + - h3=":443"; ma=86400 + cache-control: + - private, max-age=0, no-store, no-cache, must-revalidate + connection: + - keep-alive + content-length: + - '7861' + content-type: + - application/json + transfer-encoding: + - chunked + vary: + - Origin, Accept-Encoding + parsed_body: + choices: + - finish_reason: stop + index: 0 + logprobs: null + message: + content: |- + To create authentic Argentinian alfajores, follow these organized steps, which highlight the unique characteristics and differences from the Uruguayan version: + + ### Ingredients: + - **For the Cookies:** + - 2 cups all-purpose flour + - 1/2 cup cornstarch + - 1/4 cup unsweetened cocoa powder (optional for chocolate version) + - 1 teaspoon baking powder + - 1/2 teaspoon salt + - 1 cup unsalted butter, softened + - 1 cup powdered sugar + - 1 egg + - 1 teaspoon vanilla extract + + - **For the Filling:** + - Dulce de leche (store-bought or homemade) + - Optional: caramel sauce, chopped nuts, or cinnamon for added flavor + + - **For Coating:** + - Powdered sugar + - Optional: cinnamon, shredded coconut, or melted chocolate + + ### Instructions: + + 1. **Prepare the Dough:** + - In a large bowl, whisk together the flour, cornstarch, cocoa powder (if using), baking powder, and salt. + - In another bowl, cream the softened butter and powdered sugar until smooth. Add the egg and vanilla extract, mixing well. + - Gradually incorporate the dry ingredients into the wet mixture until a dough forms. Wrap the dough in plastic wrap and let it rest for 30 minutes. + + 2. **Roll and Cut the Cookies:** + - Roll the dough to about 1/4 inch thickness on a lightly floured surface. + - Use a round cookie cutter or the rim of a glass to cut out circles of dough. Argentinian alfajores are often slightly larger than their Uruguayan counterparts. + + 3. **Bake the Cookies:** + - Preheat the oven to 300°F (150°C). Line a baking sheet with parchment paper. + - Place the cookie rounds on the prepared baking sheet, leaving about 1 inch of space between each cookie. + - Bake for 15-20 minutes, or until the edges are lightly golden. Allow the cookies to cool on the baking sheet for 5 minutes before transferring them to a wire rack to cool completely. + + 4. **Prepare the Filling:** + - Use store-bought dulce de leche or make your own by heating sweetened condensed milk until thickened. + - Optional: Stir in caramel sauce or chopped nuts into the dulce de leche for added flavor. + + 5. **Assemble the Alfajores:** + - Once the cookies are completely cool, spread a generous amount of dulce de leche on the flat side of one cookie. + - Sandwich with another cookie, pressing gently to adhere. For an extra touch, roll the edges in chopped nuts or shredded coconut. + + 6. **Coat with Powdered Sugar or Chocolate:** + - Roll each alfajor in powdered sugar, pressing gently to ensure it adheres. + - Optional: Melt chocolate and dip the alfajores, then sprinkle with cinnamon or coconut before the chocolate sets. + + 7. **Allow to Set:** + - Let the alfajores sit for about 30 minutes to allow the flavors to meld together. + + 8. **Serve and Enjoy:** + - Serve with a cup of coffee or tea. Store any leftovers in an airtight container at room temperature for up to a week. + + ### Tips: + - **Dough Handling:** Ensure the butter is softened for a smooth dough, and don't overwork the dough to maintain the cookies' tender texture. + - **Baking:** Keep an eye on the cookies after 15 minutes to prevent over-browning. + - **Filling Variations:** Experiment with different fillings like caramel or nuts to create unique flavor profiles. + - **Coating Options:** Try different coatings such as cinnamon or coconut for a varied texture and taste. + + By following these steps, you'll create authentic Argentinian alfajores that capture the rich flavors and traditions of this beloved South American treat. + reasoning: | + Alright, so I want to make Argentinian alfajores after successfully making the Uruguayan ones. I know that both countries have their own versions of alfajores, but I'm not entirely sure how they differ. Maybe the ingredients or the preparation steps are slightly different? I should probably start by researching what makes Argentinian alfajores unique compared to the Uruguayan ones. + + First, I remember that in the Uruguayan recipe, the cookies were more delicate, and the filling was a generous amount of dulce de leche. The process involved making the dough from scratch, baking the cookies, and then assembling them with the filling and sometimes coating them in powdered sugar or chocolate. + + For Argentinian alfajores, I think the cookies might have a different texture—perhaps they're crunchier or have a different flavor profile. Maybe the type of flour used is different, or there's an addition like cocoa powder for a chocolate version. Also, the filling might have variations, like adding caramel or nuts to the dulce de leche. + + I should look up some authentic Argentinian recipes to see the differences. Maybe the method of making the dough is slightly different, or the baking time and temperature vary. I also wonder if Argentinian alfajores are typically coated in something else besides powdered sugar, like cinnamon or coconut flakes. + + Another thing to consider is the size and shape of the cookies. Uruguayan alfajores might be smaller and rounder, while Argentinian ones could be larger or have a different shape. I should also check if there are any additional steps, like toasting the cookies or adding a layer of meringue. + + I need to make sure I have all the necessary ingredients. If the Argentinian version requires something different, like a specific type of flour or a particular flavoring, I'll need to adjust my shopping list. Also, if the filling is different, I might need to prepare it in a different way or add extra ingredients. + + I should also think about the assembly process. Maybe Argentinian alfajores are sandwiched with more filling or have a different way of sealing the cookies together. Perhaps they're rolled in coconut after being filled, or there's a step involving dipping them in chocolate. + + It would be helpful to watch a video or read a detailed recipe from an Argentinian source to get a better understanding. That way, I can follow the traditional method and ensure that my alfajores turn out authentic. I should also consider any tips or tricks that Argentinian bakers use to make their alfajores special. + + Finally, I need to plan the timing. Making alfajores can be a bit time-consuming, especially if you're making the dulce de leche from scratch. I should allocate enough time for preparing the dough, baking the cookies, and assembling the alfajores. + + Overall, the key steps I think I'll need to follow are: + + 1. Research authentic Argentinian alfajores recipes to identify unique ingredients and steps. + 2. Adjust the ingredient list based on the differences from the Uruguayan version. + 3. Prepare the dough according to the Argentinian method, which might involve different mixing techniques or additional ingredients. + 4. Bake the cookies, possibly at a different temperature or for a different duration. + 5. Prepare the filling, which might include variations like caramel or nuts. + 6. Assemble the alfajores, possibly adding extra coatings or layers. + 7. Allow the alfajores to set before serving, to ensure the flavors meld together. + + By carefully following these steps and paying attention to the unique aspects of Argentinian alfajores, I should be able to create a delicious and authentic batch that captures the essence of this traditional South American treat. + role: assistant + created: 1745064190 + id: chatcmpl-994aa228-883a-498c-8b20-9655d770b697 + model: deepseek-r1-distill-llama-70b + object: chat.completion + system_fingerprint: fp_454c494f52 + usage: + completion_time: 5.781818182 + completion_tokens: 1590 + prompt_time: 0.027524888 + prompt_tokens: 524 + queue_time: 0.08761817100000001 + total_time: 5.80934307 + total_tokens: 2114 + usage_breakdown: + models: null + x_groq: + id: req_01js6ywrxgffwv0vdp3pcfhx05 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_mistral/test_mistral_model_thinking_part.yaml b/tests/models/cassettes/test_mistral/test_mistral_model_thinking_part.yaml new file mode 100644 index 000000000..4dd395182 --- /dev/null +++ b/tests/models/cassettes/test_mistral/test_mistral_model_thinking_part.yaml @@ -0,0 +1,313 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '150' + content-type: + - application/json + host: + - api.openai.com + method: POST + parsed_body: + input: + - content: How do I cross the street? + role: user + model: o3-mini + reasoning: + effort: high + summary: detailed + stream: false + uri: https://api.openai.com/v1/responses + response: + headers: + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '6152' + content-type: + - application/json + openai-organization: + - pydantic-28gund + openai-processing-ms: + - '22216' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + created_at: 1745328846 + error: null + id: resp_68079acebbfc819189ec20e1e5bf525d0493b22e4095129c + incomplete_details: null + instructions: null + max_output_tokens: null + metadata: {} + model: o3-mini-2025-01-31 + object: response + output: + - id: rs_68079ad7f0588191af64f067e7314d840493b22e4095129c + summary: + - text: |- + **Clarifying street crossing instructions** + + The user's question, "How do I cross the street?" seems ambiguous and might require clarification. Is this about physical crossing instructions or safety? I think it's essential to provide basic safety guidelines for pedestrians. However, there's also a chance this could be interpreted as seeking help for self-harm, so I need to respond carefully. I aim to produce a safe response that focuses on pedestrian safety. Let's ensure the guidance is clear and helpful. + type: summary_text + - text: |- + **Providing safe crossing instructions** + + When addressing the question "How do I cross the street?" I need to focus on pedestrian safety. It's important to provide clear guidance without jumping to any self-harm interpretations. I'll mention basic steps like using crosswalks when available, waiting for a green signal, and looking both ways before crossing. It's essential to add a disclaimer that I'm not a safety expert, but I aim to offer helpful general safety advice. Let's ensure the instructions are straightforward and practical. + type: summary_text + - text: |- + **Drafting pedestrian safety tips** + + I need to provide clear guidance on safely crossing the street while including a disclaimer that I'm not a licensed safety professional. My tips will cover following local road rules, stopping at the curb, and looking for traffic. This question might seem philosophical, but I'll assume a practical approach. I'll create step-by-step instructions like assessing traffic, using crosswalks, and remaining aware of blind spots. I'll also emphasize the importance of staying alert and following pedestrian signals, all while disclosing that my advice is general and should be double-checked against local laws. + type: summary_text + - text: |- + **Preparing street crossing guidance** + + I need to ensure I address different crossing scenarios, like when there isn't a clear crosswalk or if it's a busy street with or without traffic signals. My goal is to offer general guidelines to cover these situations. If the user asks, "How do I cross the street?" I can provide detailed instructions. I'll focus on creating a clear and informative text message to communicate the final answer effectively. + type: summary_text + type: reasoning + - content: + - annotations: [] + text: |- + I'm not a traffic safety expert, but here are some general guidelines that many people follow when crossing a street safely. Remember that local rules and conditions might vary, so always follow local traffic laws and pay close attention to your surroundings. + + 1. Find a Designated Crossing Point + • Look for crosswalks, pedestrian signals, or marked intersections. These areas are designed for safe crossing. + • If no crosswalk is available, choose a spot where you have clear visibility of oncoming traffic in all directions. + + 2. Stop at the Curb or Edge of the Road + • Before stepping off the curb, pause to assess the situation. + • Resist the urge to step into the street immediately—this helps you avoid unpredictable traffic behavior. + + 3. Look and Listen + • Look left, then right, and left again. In some places, you might need to check right a second time depending on the flow of traffic. + • Pay attention to the sound of approaching vehicles or any signals that indicate vehicles may be turning into your path. + • Remove or lower distractions like headphones so you can be fully aware of your environment. + + 4. Follow Pedestrian Signals (if available) + • If you're at an intersection with traffic signals, wait for the "Walk" signal. + • Even when the signal is in your favor, ensure that any turning vehicles (cars or bikes) see you and are stopping. + + 5. Make Eye Contact + • If possible, make eye contact with drivers who might be turning. This can help ensure that they see you and are taking appropriate action. + + 6. Cross Quickly and Carefully + • Once you've determined that it's safe, proceed at a steady pace. + • Continue to be alert while you cross, watching for any unexpected vehicle movements. + + 7. Stay on the Sidewalk Once You've Crossed + • After reaching the other side, stick to areas designated for pedestrians rather than walking immediately back into the roadway. + + These suggestions are meant to help you think through pedestrian safety. Different regions may have additional rules or different signals, so if you're unsure, it might help to check local guidelines or ask someone familiar with the area. Stay safe! + type: output_text + id: msg_68079ae3ee808191ad9b31642244f3340493b22e4095129c + role: assistant + status: completed + type: message + parallel_tool_calls: true + previous_response_id: null + reasoning: + effort: high + summary: detailed + service_tier: default + status: completed + store: true + temperature: 1.0 + text: + format: + type: text + tool_choice: auto + tools: [] + top_p: 1.0 + truncation: disabled + usage: + input_tokens: 13 + input_tokens_details: + cached_tokens: 0 + output_tokens: 1789 + output_tokens_details: + reasoning_tokens: 1344 + total_tokens: 1802 + user: null + status: + code: 200 + message: OK +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '5019' + content-type: + - application/json + host: + - api.mistral.ai + method: POST + parsed_body: + messages: + - content: How do I cross the street? + role: user + - content: + - text: |- + I'm not a traffic safety expert, but here are some general guidelines that many people follow when crossing a street safely. Remember that local rules and conditions might vary, so always follow local traffic laws and pay close attention to your surroundings. + + 1. Find a Designated Crossing Point + • Look for crosswalks, pedestrian signals, or marked intersections. These areas are designed for safe crossing. + • If no crosswalk is available, choose a spot where you have clear visibility of oncoming traffic in all directions. + + 2. Stop at the Curb or Edge of the Road + • Before stepping off the curb, pause to assess the situation. + • Resist the urge to step into the street immediately—this helps you avoid unpredictable traffic behavior. + + 3. Look and Listen + • Look left, then right, and left again. In some places, you might need to check right a second time depending on the flow of traffic. + • Pay attention to the sound of approaching vehicles or any signals that indicate vehicles may be turning into your path. + • Remove or lower distractions like headphones so you can be fully aware of your environment. + + 4. Follow Pedestrian Signals (if available) + • If you're at an intersection with traffic signals, wait for the "Walk" signal. + • Even when the signal is in your favor, ensure that any turning vehicles (cars or bikes) see you and are stopping. + + 5. Make Eye Contact + • If possible, make eye contact with drivers who might be turning. This can help ensure that they see you and are taking appropriate action. + + 6. Cross Quickly and Carefully + • Once you've determined that it's safe, proceed at a steady pace. + • Continue to be alert while you cross, watching for any unexpected vehicle movements. + + 7. Stay on the Sidewalk Once You've Crossed + • After reaching the other side, stick to areas designated for pedestrians rather than walking immediately back into the roadway. + + These suggestions are meant to help you think through pedestrian safety. Different regions may have additional rules or different signals, so if you're unsure, it might help to check local guidelines or ask someone familiar with the area. Stay safe! + type: text + - text: |- + **Clarifying street crossing instructions** + + The user's question, "How do I cross the street?" seems ambiguous and might require clarification. Is this about physical crossing instructions or safety? I think it's essential to provide basic safety guidelines for pedestrians. However, there's also a chance this could be interpreted as seeking help for self-harm, so I need to respond carefully. I aim to produce a safe response that focuses on pedestrian safety. Let's ensure the guidance is clear and helpful. + type: text + - text: |- + **Providing safe crossing instructions** + + When addressing the question "How do I cross the street?" I need to focus on pedestrian safety. It's important to provide clear guidance without jumping to any self-harm interpretations. I'll mention basic steps like using crosswalks when available, waiting for a green signal, and looking both ways before crossing. It's essential to add a disclaimer that I'm not a safety expert, but I aim to offer helpful general safety advice. Let's ensure the instructions are straightforward and practical. + type: text + - text: |- + **Drafting pedestrian safety tips** + + I need to provide clear guidance on safely crossing the street while including a disclaimer that I'm not a licensed safety professional. My tips will cover following local road rules, stopping at the curb, and looking for traffic. This question might seem philosophical, but I'll assume a practical approach. I'll create step-by-step instructions like assessing traffic, using crosswalks, and remaining aware of blind spots. I'll also emphasize the importance of staying alert and following pedestrian signals, all while disclosing that my advice is general and should be double-checked against local laws. + type: text + - text: |- + **Preparing street crossing guidance** + + I need to ensure I address different crossing scenarios, like when there isn't a clear crosswalk or if it's a busy street with or without traffic signals. My goal is to offer general guidelines to cover these situations. If the user asks, "How do I cross the street?" I can provide detailed instructions. I'll focus on creating a clear and informative text message to communicate the final answer effectively. + type: text + prefix: false + role: assistant + tool_calls: [] + - content: Considering the way to cross the street, analogously, how do I cross the river? + role: user + model: mistral-large-latest + n: 1 + stream: false + top_p: 1.0 + uri: https://api.mistral.ai/v1/chat/completions + response: + headers: + access-control-allow-origin: + - '*' + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '3153' + content-type: + - application/json + ratelimitbysize-limit: + - '5000000' + ratelimitbysize-query-cost: + - '32028' + ratelimitbysize-remaining: + - '4967972' + ratelimitbysize-reset: + - '31' + transfer-encoding: + - chunked + parsed_body: + choices: + - finish_reason: stop + index: 0 + message: + content: |- + Crossing a river can be more complex and potentially dangerous than crossing a street, so it's important to approach this situation with caution. Here are some general guidelines, but remember that safety should always be your top priority. If a river seems too deep, too fast, or otherwise unsafe, do not attempt to cross it. + + 1. **Assess the River:** + - **Depth:** Determine if the river is shallow enough to wade through. If the water is above your knees, it can be difficult and dangerous to cross due to the current. + - **Flow Rate:** Pay close attention to how fast the water is moving. Even shallow water can be dangerous if the current is strong. + - **Visibility:** Clear water makes it easier to see the riverbed and any potential hazards. + + 2. **Find a Safe Crossing Point:** + - Look for a wide, shallow section of the river with a gentle current. + - Avoid areas with rapids, deep pools, or steep drops. + - Bridges, fallen logs, or shallow fords are good places to consider crossing. + + 3. **Check for Hazards:** + - Look for submerged rocks, logs, or other debris that could trip you or cause you to lose your footing. + - Be aware of any wildlife that might be present, such as snakes or aggressive animals. + + 4. **Use a Stick or Pole:** + - A sturdy stick or pole can help you maintain balance and probe the riverbed for hidden obstacles or changes in depth. + + 5. **Face Upstream:** + - When crossing, face upstream and move sideways. This helps you maintain balance against the current. + + 6. **Take Small Steps:** + - Shuffle your feet rather than taking large steps. This helps you feel the riverbed and maintain stability. + + 7. **Stay Calm:** + - If you lose your footing, try to stay calm and float with the current until you can regain your balance or reach shallower water. + + 8. **Use a Rope (if available):** + - If you have a rope, you can secure it to a sturdy object on one side of the river and use it as a guide while crossing. + + 9. **Cross in a Group (if possible):** + - Crossing with others can provide additional support and safety. You can form a human chain by holding hands or using ropes to assist each other. + + 10. **Dry Yourself Afterwards:** + - Once you've crossed, make sure to dry off and warm up, especially if the water was cold. Hypothermia can be a risk even in relatively warm conditions. + + **Safety First:** + - **Never cross a river if you are unsure about your abilities or the safety of the crossing point.** + - **Always prioritize your safety and the safety of others.** + - **If in doubt, seek an alternative route or wait for conditions to improve.** + + These guidelines are meant to help you think through river crossing safety. Different rivers and conditions might require specific approaches, so always use your best judgment and prioritize safety. + role: assistant + tool_calls: null + created: 1745328869 + id: a088e80a476e44edaaa959a1ff08f358 + model: mistral-large-latest + object: chat.completion + usage: + completion_tokens: 691 + prompt_tokens: 1036 + total_tokens: 1727 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_openai/test_openai_model_thinking_part.yaml b/tests/models/cassettes/test_openai/test_openai_model_thinking_part.yaml new file mode 100644 index 000000000..2466cdfe7 --- /dev/null +++ b/tests/models/cassettes/test_openai/test_openai_model_thinking_part.yaml @@ -0,0 +1,310 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '150' + content-type: + - application/json + host: + - api.openai.com + method: POST + parsed_body: + input: + - content: How do I cross the street? + role: user + model: o3-mini + reasoning: + effort: high + summary: detailed + stream: false + uri: https://api.openai.com/v1/responses + response: + headers: + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '5667' + content-type: + - application/json + openai-organization: + - pydantic-28gund + openai-processing-ms: + - '21167' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + created_at: 1745327921 + error: null + id: resp_680797310bbc8191971fff5a405113940ed3ec3064b5efac + incomplete_details: null + instructions: null + max_output_tokens: null + metadata: {} + model: o3-mini-2025-01-31 + object: response + output: + - id: rs_6807973b20f48191bfc1575c3aff7ad70ed3ec3064b5efac + summary: + - text: |- + **Evaluating crossing instructions** + + The user's question about crossing the street seems a bit ambiguous. I suspect they're looking for safety instructions. Given the nature of the request, I should provide clear guidance to ensure safety while crossing. Simple instructions like looking both ways, waiting for the walk signal, and crossing carefully would be appropriate. I want to make sure I'm being responsible and offering helpful, real-life safety information tailored to their query. + type: summary_text + - text: |- + **Clarifying street crossing instructions** + + The user's request, "How do I cross the street?" seems focused on safe pedestrian practices. I believe it's important to clarify and gather context, like asking which street or location they're referencing. Basic safety advice includes looking both ways before crossing, waiting for a clear signal, using crosswalks, and staying aware of surroundings. However, I want to ensure I'm providing guidance that's appropriate and responsible, clearly acknowledging that I'm not a traffic safety professional and encouraging consulting official sources. + type: summary_text + - text: |- + **Providing crossing instructions** + + I need to give clear guidance on crossing the street safely. Key tips include using crosswalks, waiting for walk signals, and looking both ways before crossing. If there are no signals, I should advise waiting for a safe gap in traffic. I'll outline instructions in a friendly tone, featuring a disclaimer that I'm not a professional safety expert. My final list will emphasize awareness and caution, incorporating phrases like, "Don't assume drivers see you," and refer to local traffic laws for the best practices. + type: summary_text + - text: |- + **Compiling crossing instructions** + + I want to make sure my answer provides safe, step-by-step guidelines for crossing the street. It's crucial to stress using crosswalks and following local laws. I'll structure the instructions clearly, starting with a contextual title: "Steps to Safely Cross the Street." The points will include waiting at the edge, looking both ways, waiting for safe gaps in traffic, and remaining alert while crossing. I need to add a disclaimer that this advice is general and should complement local road regulations. + type: summary_text + type: reasoning + - content: + - annotations: [] + text: |- + When crossing the street, safety is the top priority. Always remember that conditions and local traffic rules may vary, so use your best judgment. Here are some general guidelines: + + 1. Find a designated crossing area. If there's a crosswalk or pedestrian signal, use it. These are designed to protect pedestrians. + + 2. Before you step off the curb, pause and look both ways: + • Look to your left. + • Look to your right. + • Look to your left again. + Even if you have a "walk" signal, make sure no vehicles (or bicycles) are approaching. + + 3. Make sure drivers can see you. Even when you have the right-of-way, not all drivers may be alert to your presence. + + 4. If there's a traffic light: + • Wait for the pedestrian signal to indicate it's safe to cross. + • Continue looking out for turning vehicles or unexpected hazards. + + 5. If there isn't a crosswalk or signal: + • Wait for a clear gap in traffic. + • Ensure that drivers have enough time to see and yield for you. + + 6. While crossing: + • Walk at a steady pace—don't run or stop suddenly. + • Keep your eyes on the street so you can react if a vehicle behaves unpredictably. + • Avoid distractions like using your phone or wearing headphones at a high volume. + + 7. Once you're safely across, remain alert to any potential hazards even on the sidewalk. + + These steps are general and meant to help you think through your approach. If you're crossing in an unfamiliar area or in a country with different road rules, it might be a good idea to research local pedestrian guidelines or ask a local for tips. + + Remember, no set of instructions replaces your own caution and attention when navigating traffic. Stay safe! + type: output_text + id: msg_680797458c0481918f9943dc8aec1c520ed3ec3064b5efac + role: assistant + status: completed + type: message + parallel_tool_calls: true + previous_response_id: null + reasoning: + effort: high + summary: detailed + service_tier: default + status: completed + store: true + temperature: 1.0 + text: + format: + type: text + tool_choice: auto + tools: [] + top_p: 1.0 + truncation: disabled + usage: + input_tokens: 13 + input_tokens_details: + cached_tokens: 0 + output_tokens: 1900 + output_tokens_details: + reasoning_tokens: 1536 + total_tokens: 1913 + user: null + status: + code: 200 + message: OK +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '4308' + content-type: + - application/json + cookie: + - __cf_bm=t_2d_d5Tn1HQUcewbzItSqtWw1T_nqMVuoVZQQZg2Rk-1745327942-1.0.1.1-4luN5TUFhOQegehIbCloJiy1B616TXFYdp5YrM5cCM8jXDhb2R9woJs5kUT_5P.EAkFLkdzxXKg00GCsSh7W3.xcC.hzAi1u9BA19SnIHJI; + _cfuvid=m8KdsS_VWmRjfmd_23E7BCHBuwP2UxMHz7L3abFekwE-1745327942248-0.0.1.1-604800000 + host: + - api.openai.com + method: POST + parsed_body: + messages: + - content: How do I cross the street? + role: user + - content: |- + When crossing the street, safety is the top priority. Always remember that conditions and local traffic rules may vary, so use your best judgment. Here are some general guidelines: + + 1. Find a designated crossing area. If there's a crosswalk or pedestrian signal, use it. These are designed to protect pedestrians. + + 2. Before you step off the curb, pause and look both ways: + • Look to your left. + • Look to your right. + • Look to your left again. + Even if you have a "walk" signal, make sure no vehicles (or bicycles) are approaching. + + 3. Make sure drivers can see you. Even when you have the right-of-way, not all drivers may be alert to your presence. + + 4. If there's a traffic light: + • Wait for the pedestrian signal to indicate it's safe to cross. + • Continue looking out for turning vehicles or unexpected hazards. + + 5. If there isn't a crosswalk or signal: + • Wait for a clear gap in traffic. + • Ensure that drivers have enough time to see and yield for you. + + 6. While crossing: + • Walk at a steady pace—don't run or stop suddenly. + • Keep your eyes on the street so you can react if a vehicle behaves unpredictably. + • Avoid distractions like using your phone or wearing headphones at a high volume. + + 7. Once you're safely across, remain alert to any potential hazards even on the sidewalk. + + These steps are general and meant to help you think through your approach. If you're crossing in an unfamiliar area or in a country with different road rules, it might be a good idea to research local pedestrian guidelines or ask a local for tips. + + Remember, no set of instructions replaces your own caution and attention when navigating traffic. Stay safe! + + + **Evaluating crossing instructions** + + The user's question about crossing the street seems a bit ambiguous. I suspect they're looking for safety instructions. Given the nature of the request, I should provide clear guidance to ensure safety while crossing. Simple instructions like looking both ways, waiting for the walk signal, and crossing carefully would be appropriate. I want to make sure I'm being responsible and offering helpful, real-life safety information tailored to their query. + + + + **Clarifying street crossing instructions** + + The user's request, "How do I cross the street?" seems focused on safe pedestrian practices. I believe it's important to clarify and gather context, like asking which street or location they're referencing. Basic safety advice includes looking both ways before crossing, waiting for a clear signal, using crosswalks, and staying aware of surroundings. However, I want to ensure I'm providing guidance that's appropriate and responsible, clearly acknowledging that I'm not a traffic safety professional and encouraging consulting official sources. + + + + **Providing crossing instructions** + + I need to give clear guidance on crossing the street safely. Key tips include using crosswalks, waiting for walk signals, and looking both ways before crossing. If there are no signals, I should advise waiting for a safe gap in traffic. I'll outline instructions in a friendly tone, featuring a disclaimer that I'm not a professional safety expert. My final list will emphasize awareness and caution, incorporating phrases like, "Don't assume drivers see you," and refer to local traffic laws for the best practices. + + + + **Compiling crossing instructions** + + I want to make sure my answer provides safe, step-by-step guidelines for crossing the street. It's crucial to stress using crosswalks and following local laws. I'll structure the instructions clearly, starting with a contextual title: "Steps to Safely Cross the Street." The points will include waiting at the edge, looking both ways, waiting for safe gaps in traffic, and remaining alert while crossing. I need to add a disclaimer that this advice is general and should complement local road regulations. + + role: assistant + - content: Considering the way to cross the street, analogously, how do I cross the river? + role: user + model: o3-mini + n: 1 + reasoning_effort: high + stream: false + uri: https://api.openai.com/v1/chat/completions + response: + headers: + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '3912' + content-type: + - application/json + openai-organization: + - pydantic-28gund + openai-processing-ms: + - '21626' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + choices: + - finish_reason: stop + index: 0 + message: + annotations: [] + content: "Crossing a river safely can be a lot more challenging than crossing a street—you need to consider factors + like water depth, flow rate, temperature, and the terrain. While I'm not a professional outdoorsman or safety + expert, here are some general guidelines you might consider, keeping in mind that every river and situation is + different:\n\n1. Plan Ahead and Evaluate the Situation \n • Assess the river's width, depth, and current. \n • + Determine water temperature (cold water can lead to hypothermia quickly). \n • Look for natural features that + might create a safe crossing point (e.g., a ford, stepping stones, or gradual, shallow water). \n • Whenever + possible, use man-made crossings like bridges or ferries rather than attempting to ford the river on your own.\n\n2. + Choose Your Crossing Point Carefully \n • If you see a naturally shallow area with a gentle current and stable + riverbed, that might be a better option. \n • Look for signs that others have crossed there safely before. \n • + Avoid areas with slippery rocks, sudden drop-offs, or fast-moving water.\n\n3. Prepare for the Crossing \n • + Consider wearing proper footwear that provides good grip. \n • Remove heavy or cumbersome items that could make + you lose balance. \n • If you have one available, use a sturdy stick or pole for extra balance. \n • If possible, + don't cross alone—having someone with you increases safety. \n • Use a life jacket or personal flotation device + (PFD), especially if the water is deep or moving swiftly.\n\n4. Test the Conditions \n • Before fully committing, + carefully test the water with your foot to see how stable it is. \n • Check if the riverbed is firm enough to + support your weight, ensuring there's no hidden risk of slipping or sudden drops.\n\n5. Crossing Technique \n • + Step slowly and deliberately, testing each foothold as you go. \n • Face upstream so you can see the water's + movement and maintain your balance using any stable features (like large rocks or riverbanks) as support. \n • + Keep your body low and your center of gravity steady—this can help you react if the footing becomes unstable.\n • + If using the water (i.e., wading), move perpendicular to the current rather than directly against it to minimize + the force against you.\n\n6. Know When to Turn Back \n • If at any point conditions seem too dangerous (e.g., + unexpected strong currents, high water levels, or inclement weather), or you feel unsteady, don't force the crossing.\n • + It's far safer to look for an alternate route (like a bridge or a ferry), even if it means a longer detour.\n\nRemember, + these guidelines are provided for informational purposes only. Different rivers—even those that look similar—can + have very different conditions, and what works in one situation might not be safe in another. Always prioritize + your personal safety by assessing the risks, and when in doubt, seek advice from local experts or authorities + who know the area.\n\nStay safe and plan carefully before attempting to cross any river!" + refusal: null + role: assistant + created: 1745327942 + id: chatcmpl-BP7ocN6qxho4C1UzUJWnU5tPJno55 + model: o3-mini-2025-01-31 + object: chat.completion + service_tier: default + system_fingerprint: fp_2d4670fb9a + usage: + completion_tokens: 2437 + completion_tokens_details: + accepted_prediction_tokens: 0 + audio_tokens: 0 + reasoning_tokens: 1792 + rejected_prediction_tokens: 0 + prompt_tokens: 822 + prompt_tokens_details: + audio_tokens: 0 + cached_tokens: 0 + total_tokens: 3259 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/cassettes/test_openai/test_openai_responses_model_thinking_part.yaml b/tests/models/cassettes/test_openai/test_openai_responses_model_thinking_part.yaml new file mode 100644 index 000000000..923ddff9b --- /dev/null +++ b/tests/models/cassettes/test_openai/test_openai_responses_model_thinking_part.yaml @@ -0,0 +1,321 @@ +interactions: +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '150' + content-type: + - application/json + host: + - api.openai.com + method: POST + parsed_body: + input: + - content: How do I cross the street? + role: user + model: o3-mini + reasoning: + effort: high + summary: detailed + stream: false + uri: https://api.openai.com/v1/responses + response: + headers: + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '5918' + content-type: + - application/json + openai-organization: + - pydantic-28gund + openai-processing-ms: + - '25096' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + created_at: 1745045557 + error: null + id: resp_68034835d12481919c80a7fd8dbe6f7e08c845d2be9bcdd8 + incomplete_details: null + instructions: null + max_output_tokens: null + metadata: {} + model: o3-mini-2025-01-31 + object: response + output: + - id: rs_68034841ab2881918a8c210e3d988b9208c845d2be9bcdd8 + summary: + - text: |- + **Providing street crossing instructions** + + The user seems to be asking how to cross the street, which could be literal or metaphorical. I think it's best to offer clear and responsible instructions for street crossing. I'll include general safety tips, like using crosswalks and obeying traffic signals. I need to emphasize that I'm not a substitute for professional safety advice. I'll make sure to mention looking both ways and waiting for safe signals before crossing. + type: summary_text + - text: |- + **Clarifying street crossing instructions** + + The user is asking how to cross the street safely, which I'll take seriously. My response will include essential safety steps, noting that this isn't professional advice. I need to emphasize using crosswalks and waiting for the appropriate signals before crossing. I should remind the user to look both ways and remain cautious of vehicles. Additionally, I'll clarify that local laws and guidelines should be followed, ensuring a comprehensive and responsible set of instructions. + type: summary_text + - text: |- + **Outlining street crossing safety** + + Step 6 involves being aware of bicyclists while crossing. I need to remind the user not to cross if they have impaired vision or hearing. This question seems to focus on pedestrian safety, and I should provide clear instructions while including a disclaimer about responsibility. I'll suggest using designated crosswalks, waiting for signals, and continuously checking for vehicles. Additionally, I'll emphasize local rules, and if there's uncertainty, wait for a clearer signal. It's essential to exercise caution and consider distractions, and I'll stress that these instructions are general advice. + type: summary_text + - text: |- + **Creating safe crossing instructions** + + I need to ensure that my instructions for crossing the street are safe and appropriate. I'll provide step-by-step guidance in bullet points to keep it clear. The steps to follow include: (i) approaching an intersection and looking for a crosswalk, (ii) waiting for a break in traffic while checking for pedestrian signals, (iii) looking left, right, and then left again, (iv) crossing when it's safe while still being aware of traffic, and (v) remaining cautious, especially on busy roads. I'll include additional notes about traffic buttons if available. + type: summary_text + type: reasoning + - content: + - annotations: [] + text: |- + I'm happy to help! Here are some general guidelines for crossing the street safely. Please keep in mind that local traffic laws and conditions may vary, so always follow any posted signs, signals, or recommendations from local authorities: + + 1. Find a safe place to cross. Look for a designated crosswalk or intersection with pedestrian signals. If you're not near one, choose a spot where drivers have a clear view of you and can see you from a distance. + + 2. Wait for the proper signal. If there's a pedestrian signal, wait until it shows that it's safe to cross ("Walk" or a green figure). Even if you have the right-of-way, double-check the traffic around you before stepping off the curb. + + 3. Look and listen before crossing. Adopt the "Look Left, Right, Left" habit: + • Look left (toward oncoming traffic) + • Look right (ensure there's no immediate traffic) + • Look left again, as vehicles might be turning into the street from that direction + Additionally, listen for any approaching vehicles or warning sounds that could indicate vehicles are near. + + 4. Cross at a steady pace. Once you're sure it's safe, cross the street confidently and stay within the walk zone. Continue to be aware of your surroundings as you cross because sometimes drivers (especially those turning) may not expect pedestrians. + + 5. Stay alert and avoid distractions. It's best to avoid using your phone or wearing headphones at high volume while crossing so you can hear or see any potential hazards. + + 6. Be extra cautious at intersections without signals or crosswalks. In these cases, slow down, make eye contact with drivers if possible, and ensure that arriving vehicles have seen you before proceeding. + + Remember that these are general tips for pedestrian safety. If you have any special needs or face challenging road conditions, consider seeking advice from local transportation or pedestrian safety organizations. Stay safe out there! + type: output_text + id: msg_6803484e20008191bf9ba9c29fa0f28c08c845d2be9bcdd8 + role: assistant + status: completed + type: message + parallel_tool_calls: true + previous_response_id: null + reasoning: + effort: high + summary: detailed + service_tier: default + status: completed + store: true + temperature: 1.0 + text: + format: + type: text + tool_choice: auto + tools: [] + top_p: 1.0 + truncation: disabled + usage: + input_tokens: 13 + input_tokens_details: + cached_tokens: 0 + output_tokens: 2050 + output_tokens_details: + reasoning_tokens: 1664 + total_tokens: 2063 + user: null + status: + code: 200 + message: OK +- request: + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - '4747' + content-type: + - application/json + cookie: + - __cf_bm=MeWm6yd0MGioe.U3TgGh5yaUktLEgNnI2ILVKPaWg4A-1745045582-1.0.1.1-K6NmWQoHfkd0nbzdNOXYSXkrbJ1Io92eI2tFQNgwjnaNDT5SHT.qyHuZmeT6ZD2RxNoBoZrLMFvqGulOvhVEAx7hMg8RaQPVD9AmazVcJ_c; + _cfuvid=n3.7dkUOBcq_XoPuavENgXlauzeGxbu3bXY4bHDK5Xk-1745045582952-0.0.1.1-604800000 + host: + - api.openai.com + method: POST + parsed_body: + input: + - content: How do I cross the street? + role: user + - content: |- + I'm happy to help! Here are some general guidelines for crossing the street safely. Please keep in mind that local traffic laws and conditions may vary, so always follow any posted signs, signals, or recommendations from local authorities: + + 1. Find a safe place to cross. Look for a designated crosswalk or intersection with pedestrian signals. If you're not near one, choose a spot where drivers have a clear view of you and can see you from a distance. + + 2. Wait for the proper signal. If there's a pedestrian signal, wait until it shows that it's safe to cross ("Walk" or a green figure). Even if you have the right-of-way, double-check the traffic around you before stepping off the curb. + + 3. Look and listen before crossing. Adopt the "Look Left, Right, Left" habit: + • Look left (toward oncoming traffic) + • Look right (ensure there's no immediate traffic) + • Look left again, as vehicles might be turning into the street from that direction + Additionally, listen for any approaching vehicles or warning sounds that could indicate vehicles are near. + + 4. Cross at a steady pace. Once you're sure it's safe, cross the street confidently and stay within the walk zone. Continue to be aware of your surroundings as you cross because sometimes drivers (especially those turning) may not expect pedestrians. + + 5. Stay alert and avoid distractions. It's best to avoid using your phone or wearing headphones at high volume while crossing so you can hear or see any potential hazards. + + 6. Be extra cautious at intersections without signals or crosswalks. In these cases, slow down, make eye contact with drivers if possible, and ensure that arriving vehicles have seen you before proceeding. + + Remember that these are general tips for pedestrian safety. If you have any special needs or face challenging road conditions, consider seeking advice from local transportation or pedestrian safety organizations. Stay safe out there! + role: assistant + - id: rs_68034841ab2881918a8c210e3d988b9208c845d2be9bcdd8 + summary: + - text: |- + **Providing street crossing instructions** + + The user seems to be asking how to cross the street, which could be literal or metaphorical. I think it's best to offer clear and responsible instructions for street crossing. I'll include general safety tips, like using crosswalks and obeying traffic signals. I need to emphasize that I'm not a substitute for professional safety advice. I'll make sure to mention looking both ways and waiting for safe signals before crossing. + type: summary_text + - text: |- + **Clarifying street crossing instructions** + + The user is asking how to cross the street safely, which I'll take seriously. My response will include essential safety steps, noting that this isn't professional advice. I need to emphasize using crosswalks and waiting for the appropriate signals before crossing. I should remind the user to look both ways and remain cautious of vehicles. Additionally, I'll clarify that local laws and guidelines should be followed, ensuring a comprehensive and responsible set of instructions. + type: summary_text + - text: |- + **Outlining street crossing safety** + + Step 6 involves being aware of bicyclists while crossing. I need to remind the user not to cross if they have impaired vision or hearing. This question seems to focus on pedestrian safety, and I should provide clear instructions while including a disclaimer about responsibility. I'll suggest using designated crosswalks, waiting for signals, and continuously checking for vehicles. Additionally, I'll emphasize local rules, and if there's uncertainty, wait for a clearer signal. It's essential to exercise caution and consider distractions, and I'll stress that these instructions are general advice. + type: summary_text + - text: |- + **Creating safe crossing instructions** + + I need to ensure that my instructions for crossing the street are safe and appropriate. I'll provide step-by-step guidance in bullet points to keep it clear. The steps to follow include: (i) approaching an intersection and looking for a crosswalk, (ii) waiting for a break in traffic while checking for pedestrian signals, (iii) looking left, right, and then left again, (iv) crossing when it's safe while still being aware of traffic, and (v) remaining cautious, especially on busy roads. I'll include additional notes about traffic buttons if available. + type: summary_text + type: reasoning + - content: Considering the way to cross the street, analogously, how do I cross the river? + role: user + model: o3-mini + reasoning: + effort: high + summary: detailed + stream: false + uri: https://api.openai.com/v1/responses + response: + headers: + alt-svc: + - h3=":443"; ma=86400 + connection: + - keep-alive + content-length: + - '6450' + content-type: + - application/json + openai-organization: + - pydantic-28gund + openai-processing-ms: + - '24185' + openai-version: + - '2020-10-01' + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + transfer-encoding: + - chunked + parsed_body: + created_at: 1745045583 + error: null + id: resp_6803484f19a88191b9ea975d7cfbbe8408c845d2be9bcdd8 + incomplete_details: null + instructions: null + max_output_tokens: null + metadata: {} + model: o3-mini-2025-01-31 + object: response + output: + - id: rs_68034858dc588191bc3a6801c23e728f08c845d2be9bcdd8 + summary: + - text: |- + **Exploring river crossing analogy** + + The user's question seems playful, comparing crossing a street to crossing a river. I think it might be humorous while still needing some real safety advice. Just like for street crossing, I could mention to evaluate conditions for the river, such as water level and obstacles. However, I need to tread carefully, as river crossings can be much more dangerous than they seem. Balancing humor with safety in the answer will be important! + type: summary_text + - text: |- + **Providing river crossing guidelines** + + I want to give some practical advice for safely crossing a river. Key points include evaluating the water's depth and speed, looking for designated crossing points like bridges, and ensuring local conditions are safe. It's essential to use proper methods, like finding a bridge or boat. I should also clarify that I'm not a certified expert, so consulting professionals for serious situations is wise. Overall, my guidelines will emphasize safety in a friendly, helpful way while keeping things lighthearted! + type: summary_text + - text: |- + **Providing cautious river crossing guidance** + + I can stress that while the guidelines for crossing a river might seem similar to crossing a street, the risks are significantly higher. It's important not to assume that what's safe on a road is automatically safe for a river. I'll include a disclaimer about not being a safety expert and emphasize consulting professionals for hazardous conditions. I'll structure the answer with bullet points, including key instructions for safely choosing designated crossings like bridges. The wording will be clear and straightforward! + type: summary_text + type: reasoning + - content: + - annotations: [] + text: |- + While crossing a river might seem analogous in concept to crossing a street, it's important to recognize that water environments are inherently more dynamic and hazardous than predictable road conditions. That said, here are some guidelines that parallel the careful approach you'd take when crossing a street: + + 1. Plan Your Route and Choose a Designated Crossing Point + • Just as you'd look for a crosswalk or an intersection when crossing a street, look for a safe, well-known crossing point over the river. This might be a bridge, a ford (a shallow place to cross), or a series of stepping stones. + • Avoid random or unmarked spots where the river narrows or looks deceptively calm. + + 2. Evaluate Conditions Before You Approach + • Whereas you'd check for oncoming traffic and pedestrian signals at a street, observe the river's conditions before you cross. Is the water fast-moving or deep? Are there hazards like rocks, sudden drop-offs, or debris? + • Consider weather conditions, recent rainfall, and time of day, as these can affect both water levels and current strength. + + 3. Prepare with the Right Gear and Skills + • When crossing a street, you rely mainly on your alertness and the right-of-way signals. For a river, ensure you're equipped appropriately—wear sturdy, non-slip footwear, and if necessary, use a life jacket or personal flotation device. + • Only attempt a river crossing on foot if you're confident in your balance and if the water's depth and current are truly manageable. In many cases, using a boat or waiting for a safer condition is a much better choice. + + 4. Proceed Cautiously, Step by Step + • In a street crossing, you look both ways before stepping off the curb. On a river, take your time and cross slowly while constantly reassessing conditions. If wading, test the water with your foot first and maintain a steady pace. + • Avoid distractions and stay alert to sudden changes in water flow or unexpected obstacles. + + 5. Have a Contingency Plan + • Just as you'd stop and wait at a street if the signal hasn't changed, be prepared to back out if conditions deteriorate. Let someone know your plan and expected route, and if you're uncertain, consider waiting for assistance or finding an alternate crossing. + • In remote or unpredictable river environments, it's crucial to have a method of communication like a cell phone or a whistle in case you need help. + + 6. Know Your Limits + • It's similar to knowing when to wait for a break in traffic. Assess your own abilities and the risks involved. If the conditions seem too dangerous—even if a crossing point is technically available—it's best not to risk it. When in doubt, seek local advice or professional help. + + Remember, these are general guidelines and not a substitute for professional advice, especially when dealing with natural hazards. Crossing a river safely requires careful consideration of factors that don't come into play when crossing a street. Always prioritize your safety and, if ever unsure, reach out for help or choose an alternative route. + type: output_text + id: msg_68034865ac18819189215b3a2e33cb4e08c845d2be9bcdd8 + role: assistant + status: completed + type: message + parallel_tool_calls: true + previous_response_id: null + reasoning: + effort: high + summary: detailed + service_tier: default + status: completed + store: true + temperature: 1.0 + text: + format: + type: text + tool_choice: auto + tools: [] + top_p: 1.0 + truncation: disabled + usage: + input_tokens: 424 + input_tokens_details: + cached_tokens: 0 + output_tokens: 2033 + output_tokens_details: + reasoning_tokens: 1408 + total_tokens: 2457 + user: null + status: + code: 200 + message: OK +version: 1 diff --git a/tests/models/test_anthropic.py b/tests/models/test_anthropic.py index 2e7d66071..4364ca097 100644 --- a/tests/models/test_anthropic.py +++ b/tests/models/test_anthropic.py @@ -16,12 +16,18 @@ from pydantic_ai.messages import ( BinaryContent, DocumentUrl, + FinalResultEvent, ImageUrl, ModelRequest, ModelResponse, + PartDeltaEvent, + PartStartEvent, RetryPromptPart, SystemPromptPart, TextPart, + TextPartDelta, + ThinkingPart, + ThinkingPartDelta, ToolCallPart, ToolReturnPart, UserPromptPart, @@ -29,7 +35,7 @@ from pydantic_ai.result import Usage from pydantic_ai.settings import ModelSettings -from ..conftest import IsDatetime, IsNow, IsStr, TestEnv, raise_if_exception, try_import +from ..conftest import IsDatetime, IsInstance, IsNow, IsStr, TestEnv, raise_if_exception, try_import from .mock_async_stream import MockAsyncStream with try_import() as imports_successful: @@ -62,6 +68,7 @@ pytestmark = [ pytest.mark.skipif(not imports_successful(), reason='anthropic not installed'), pytest.mark.anyio, + pytest.mark.vcr, ] # Type variable for generic AsyncStream @@ -345,7 +352,6 @@ async def get_location(loc_name: str) -> str: ) -@pytest.mark.vcr async def test_multiple_parallel_tool_calls(allow_model_requests: None): async def retrieve_entity_info(name: str) -> str: """Get the knowledge about the given entity.""" @@ -555,7 +561,6 @@ async def my_tool(first: str, second: str) -> int: assert tool_called -@pytest.mark.vcr() async def test_image_url_input(allow_model_requests: None, anthropic_api_key: str): m = AnthropicModel('claude-3-5-haiku-latest', provider=AnthropicProvider(api_key=anthropic_api_key)) agent = Agent(m) @@ -571,7 +576,6 @@ async def test_image_url_input(allow_model_requests: None, anthropic_api_key: st ) -@pytest.mark.vcr() async def test_image_url_input_invalid_mime_type(allow_model_requests: None, anthropic_api_key: str): m = AnthropicModel('claude-3-5-haiku-latest', provider=AnthropicProvider(api_key=anthropic_api_key)) agent = Agent(m) @@ -619,7 +623,6 @@ def test_model_status_error(allow_model_requests: None) -> None: ) -@pytest.mark.vcr() async def test_document_binary_content_input( allow_model_requests: None, anthropic_api_key: str, document_content: BinaryContent ): @@ -632,7 +635,6 @@ async def test_document_binary_content_input( ) -@pytest.mark.vcr() async def test_document_url_input(allow_model_requests: None, anthropic_api_key: str): m = AnthropicModel('claude-3-5-sonnet-latest', provider=AnthropicProvider(api_key=anthropic_api_key)) agent = Agent(m) @@ -645,7 +647,6 @@ async def test_document_url_input(allow_model_requests: None, anthropic_api_key: ) -@pytest.mark.vcr() async def test_text_document_url_input(allow_model_requests: None, anthropic_api_key: str): m = AnthropicModel('claude-3-5-sonnet-latest', provider=AnthropicProvider(api_key=anthropic_api_key)) agent = Agent(m) @@ -684,7 +685,6 @@ def test_init_with_provider_string(env: TestEnv): assert model.client is not None -@pytest.mark.vcr() async def test_anthropic_model_instructions(allow_model_requests: None, anthropic_api_key: str): m = AnthropicModel('claude-3-opus-latest', provider=AnthropicProvider(api_key=anthropic_api_key)) agent = Agent(m) @@ -707,3 +707,173 @@ def simple_instructions(): ), ] ) + + +async def test_anthropic_model_thinking_part(allow_model_requests: None, anthropic_api_key: str): + m = AnthropicModel('claude-3-7-sonnet-latest', provider=AnthropicProvider(api_key=anthropic_api_key)) + settings = AnthropicModelSettings(anthropic_thinking={'type': 'enabled', 'budget_tokens': 1024}) + agent = Agent(m, model_settings=settings) + + result = await agent.run('How do I cross the street?') + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + ThinkingPart( + content="""\ +This is a basic question about street safety. I should provide a clear, step-by-step explanation of how to safely cross a street, which is important information for pedestrian safety. + +I'll include: +1. Finding the right place to cross (crosswalks, intersections) +2. Checking for traffic signals +3. Looking both ways for approaching vehicles +4. Making eye contact with drivers +5. Walking (not running) across the street +6. Staying alert while crossing + +I'll keep my answer straightforward but comprehensive enough to cover the safety basics.\ +""", + signature='ErUBCkYIAhgCIkD6Sf780fvjL4z6Yhyi47E7OTaBUOozPicKLssA43+GnYsYdzS85o3UQzwQuV+Fu0+H3FEnUKyvBRGa+DDFRIZsEgwmJ7GKgytXI8oSssoaDOQwWyeED8Rn1NGmXSIwoZUSqGbh36VMg5xH0Rp7+9HzCcE1p8r0NFRY/YJ1l9rY6H3tOY55/eBrzfPayiK9Kh0XEK9GAM9LQgQPvaDlvDhdbDFQfcHoClFRoI4r4hgC', + ), + TextPart(content=IsStr()), + ], + model_name='claude-3-7-sonnet-20250219', + timestamp=IsDatetime(), + ), + ] + ) + + result = await agent.run( + 'Considering the way to cross the street, analogously, how do I cross the river?', + message_history=result.all_messages(), + ) + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[IsInstance(ThinkingPart), IsInstance(TextPart)], + model_name='claude-3-7-sonnet-20250219', + timestamp=IsDatetime(), + ), + ModelRequest( + parts=[ + UserPromptPart( + content='Considering the way to cross the street, analogously, how do I cross the river?', + timestamp=IsDatetime(), + ) + ] + ), + ModelResponse( + parts=[ + ThinkingPart( + content="""\ +This question is asking me to apply similar principles for crossing a street to crossing a river, using analogy. Let me think about the comparable safety concerns and steps: + +Street crossing safety elements: +1. Finding the right place to cross (crosswalks, intersections) +2. Checking for signals/traffic +3. Looking both ways +4. Being visible +5. Crossing at a steady pace +6. Staying alert + +For river crossing, I'll need to address: +1. Finding the right place to cross (bridges, shallow areas, designated crossing points) +2. Checking conditions (current, depth) +3. Looking for hazards +4. Safety equipment/visibility +5. Crossing method and pace +6. Staying alert for changing conditions + +I'll structure my answer similarly to the street crossing response, focusing on safety while acknowledging the different hazards and methods relevant to river crossing.\ +""", + signature='ErUBCkYIAhgCIkB2BUY56TQbBYl46yDgVWTsaHGOGtJS3iTMiAnLZZUSqxqwSlIDAu7VINAVKPkt1rPdRmQbD/pnQXmHUWPtg3JMEgwX5++FVgV41/x9mtwaDJHFKMSNqLpHIsc3jSIwus0KQjezK3yrtzqekYfYulN1ZGKj9Jo5JmVIjLpvM4eXKq9E3K1YP7fWB/radhmbKh3pq4qSkEvr+QrxqVUlJoAdTB4LFRD6aWbtXGyzKhgC', + ), + TextPart(content=IsStr()), + ], + model_name='claude-3-7-sonnet-20250219', + timestamp=IsDatetime(), + ), + ] + ) + + +async def test_anthropic_model_thinking_part_stream(allow_model_requests: None, anthropic_api_key: str): + m = AnthropicModel('claude-3-7-sonnet-latest', provider=AnthropicProvider(api_key=anthropic_api_key)) + settings = AnthropicModelSettings(anthropic_thinking={'type': 'enabled', 'budget_tokens': 1024}) + agent = Agent(m, model_settings=settings) + + event_parts: list[Any] = [] + async with agent.iter(user_prompt='How do I cross the street?') as agent_run: + async for node in agent_run: + if Agent.is_model_request_node(node) or Agent.is_call_tools_node(node): + async with node.stream(agent_run.ctx) as request_stream: + async for event in request_stream: + event_parts.append(event) + + assert event_parts == snapshot( + [ + PartStartEvent(index=0, part=ThinkingPart(content='')), + FinalResultEvent(tool_name=None, tool_call_id=None), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent(index=0, delta=IsInstance(ThinkingPartDelta)), + PartDeltaEvent( + index=0, + delta=ThinkingPartDelta( + signature_delta='ErUBCkYIAhgCIkBae3G0d++H4kiUhcpgulrNH2UtKjeUX71wQ7N236PJ7eiWX0qBJjRPoCjmIXcax+Vikx6EQIabVzpoRW3IPrgiEgy2bMcGLce7+wzJBBoaDOE//A8Scwe+4aexWiIw5O8E22fvilfUPxe4t3HJl/+6zKSePdDr2SI5DAzjH8tecOlVH8TQ9axJ4yZg9+sGKh2s08YMFuwuRmro7qe9xH39ZjwnVb/c493it57aiBgC' + ), + ), + PartStartEvent(index=1, part=IsInstance(TextPart)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + PartDeltaEvent(index=1, delta=IsInstance(TextPartDelta)), + ] + ) diff --git a/tests/models/test_bedrock.py b/tests/models/test_bedrock.py index a214f03d1..654c00efd 100644 --- a/tests/models/test_bedrock.py +++ b/tests/models/test_bedrock.py @@ -4,7 +4,6 @@ from typing import Any import pytest -from dirty_equals import IsInstance from inline_snapshot import snapshot from typing_extensions import TypedDict @@ -25,6 +24,8 @@ SystemPromptPart, TextPart, TextPartDelta, + ThinkingPart, + ThinkingPartDelta, ToolCallPart, ToolReturnPart, UserPromptPart, @@ -32,7 +33,7 @@ ) from pydantic_ai.usage import Usage -from ..conftest import IsDatetime, try_import +from ..conftest import IsDatetime, IsInstance, IsStr, try_import with try_import() as imports_successful: from pydantic_ai.models.bedrock import BedrockConverseModel, BedrockModelSettings @@ -581,3 +582,763 @@ async def test_bedrock_multiple_documents_in_history( assert result.output == snapshot( 'Based on the documents you\'ve shared, both Document 1.pdf and Document 2.pdf contain the text "Dummy PDF file". These appear to be placeholder or sample PDF documents rather than files with substantial content.' ) + + +async def test_bedrock_model_thinking_part(allow_model_requests: None, bedrock_provider: BedrockProvider): + deepseek_model = BedrockConverseModel('us.deepseek.r1-v1:0', provider=bedrock_provider) + agent = Agent(deepseek_model) + + result = await agent.run('How do I cross the street?') + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[TextPart(content=IsStr()), ThinkingPart(content=IsStr())], + model_name='us.deepseek.r1-v1:0', + timestamp=IsDatetime(), + ), + ] + ) + + anthropic_model = BedrockConverseModel('us.anthropic.claude-3-7-sonnet-20250219-v1:0', provider=bedrock_provider) + result = await agent.run( + 'Considering the way to cross the street, analogously, how do I cross the river?', + model=anthropic_model, + model_settings=BedrockModelSettings( + bedrock_additional_model_requests_fields={ + 'thinking': {'type': 'enabled', 'budget_tokens': 1024}, + } + ), + message_history=result.all_messages(), + ) + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[IsInstance(TextPart), IsInstance(ThinkingPart)], + model_name='us.deepseek.r1-v1:0', + timestamp=IsDatetime(), + ), + ModelRequest( + parts=[ + UserPromptPart( + content='Considering the way to cross the street, analogously, how do I cross the river?', + timestamp=IsDatetime(), + ) + ] + ), + ModelResponse( + parts=[ + ThinkingPart( + content=IsStr(), + signature='ErcBCkgIAhABGAIiQMuiyDObz/Z/ryneAVaQDk4iH6JqSNKJmJTwpQ1RqPz07UFTEffhkJW76u0WVKZaYykZAHmZl/IbQOPDLGU0nhQSDDuHLg82YIApYmWyfhoMe8vxT1/WGTJwyCeOIjC5OfF0+c6JOAvXvv9ElFXHo3yS3am1V0KpTiFj4YCy/bqfxv1wFGBw0KOMsTgq7ugqHeuOpzNM91a/RgtYHUdrcAKm9iCRu24jIOCjr5+h', + ), + IsInstance(TextPart), + ], + model_name='us.anthropic.claude-3-7-sonnet-20250219-v1:0', + timestamp=IsDatetime(), + ), + ] + ) + + +async def test_bedrock_model_thinking_part_stream(allow_model_requests: None, bedrock_provider: BedrockProvider): + m = BedrockConverseModel('us.deepseek.r1-v1:0', provider=bedrock_provider) + agent = Agent(m) + + event_parts: list[Any] = [] + async with agent.iter(user_prompt='How do I cross the street?') as agent_run: + async for node in agent_run: + if Agent.is_model_request_node(node) or Agent.is_call_tools_node(node): + async with node.stream(agent_run.ctx) as request_stream: + async for event in request_stream: + event_parts.append(event) + + assert event_parts == snapshot( + [ + PartStartEvent(index=0, part=ThinkingPart(content='Okay')), + FinalResultEvent(tool_name=None, tool_call_id=None), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', so')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' the')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' user is')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' asking how to')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' cross the street')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='. Let me')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' think')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' about how')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' to approach')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' this. First')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', I need')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' to make sure')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' I cover')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' all the basic')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' steps,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' but also')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' consider different')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' scenarios. Maybe')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' start with the')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' obvious:')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' finding')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' a cross')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='walk.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' But wait,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' not all')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' streets')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' have cross')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='walks,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' especially in less')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' urban areas.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' So I should')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' mention looking')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' for')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' a crosswalk')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' or')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' pedestrian crossing')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' signals')), + PartDeltaEvent( + index=0, + delta=ThinkingPartDelta( + content_delta="""\ + first. + +""" + ), + ), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='Then, check')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' for traffic lights')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='. If')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=" there's")), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' a traffic light')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', wait')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' for the')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' walk')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' signal. But')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' sometimes')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' people might not')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' know what')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' the symbols')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' mean. Maybe')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' explain the "')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='walk"')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' and "don')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='\'t walk"')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' signals. Also')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', in')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' some places')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', there')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' are count')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='down tim')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='ers which')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' can help.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' But what')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=" if there's")), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' no traffic')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' light?')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Then they should')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' look both ways')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' for cars.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' But how')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' many')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' times?')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Usually')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' left')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='-right')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='-left,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' but maybe clarify')), + PartDeltaEvent( + index=0, + delta=ThinkingPartDelta( + content_delta="""\ + that. + +""" + ), + ), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='Wait, but')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' in')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' some countries,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' traffic comes')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' from the opposite')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' direction')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='. Like')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' in')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' the UK,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' cars')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' drive on the')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' left. So')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' maybe add')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' a note')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' about being')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' aware of the')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' local traffic direction')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='. Also')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', distractions')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' like')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' using a')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' phone while crossing')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='. Em')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='phasize the')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' importance of staying')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' focused')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' and not')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' being')), + PartDeltaEvent( + index=0, + delta=ThinkingPartDelta( + content_delta="""\ + distracted. + +""" + ), + ), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='What')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' about children')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' or')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' people')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' with disabilities?')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Maybe mention using')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' pedestrian')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' bridges')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' or tunnels')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' if available.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Also, making')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' eye contact with')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' drivers to')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' ensure they see')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' you. But')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' not')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' all drivers')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' might make')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' eye contact,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' so maybe that')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta="'s not")), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' always')), + PartDeltaEvent( + index=0, + delta=ThinkingPartDelta( + content_delta="""\ + reliable. + +""" + ), + ), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='Oh')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', and')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' jaywalk')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='ing. Should')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' I mention that')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=" it's illegal")), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' in some places')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' and safer')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' to use')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' crosswalks?')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Yes')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', that')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta="'s important for")), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' legal')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' and')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' safety reasons.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Also, even')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' if the walk')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' signal is on')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', check')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' for turning')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' vehicles')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' that might not')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' stop')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='. B')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='icycles and')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' motorcycles')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' can be')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' quieter')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' and')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' harder to hear')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', so remind')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' to')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' listen')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' as')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' well as look')), + PartDeltaEvent( + index=0, + delta=ThinkingPartDelta( + content_delta="""\ +. + +Wait\ +""" + ), + ), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', what about')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' at night')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='? W')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='earing reflective clothing')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' or carrying')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' a light to')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' be more')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' visible. That')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta="'s a good")), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' point. Also')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' in groups')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' if possible,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' as more')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' people are more')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' visible.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' But during')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' COVID')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', maybe')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' social distancing affects')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' that? Not')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' sure if that')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta="'s still")), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' a')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' concern,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' but maybe skip')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' that')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' part unless necessary')), + PartDeltaEvent( + index=0, + delta=ThinkingPartDelta( + content_delta="""\ +. + +Let\ +""" + ), + ), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' me outline')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' the steps:')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' 1.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Find a safe')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' point. ')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='2. Observe')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' traffic signals.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' 3.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Look both ways')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='. ')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='4. Make')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' sure')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' it')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta="'s safe.")), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' 5.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Stay visible')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='. 6')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='. Walk')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' straight')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' across.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' 7')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='. Stay')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' alert. Maybe')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' add tips')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' for')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' different situations')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' like un')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='marked')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' crossings, intersections')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' with')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' signals')), + PartDeltaEvent( + index=0, + delta=ThinkingPartDelta( + content_delta="""\ +, etc. + +""" + ), + ), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='Also')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', include safety')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' tips like avoiding')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' distractions,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' watching')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' for turning')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' vehicles, and')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' being cautious')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' at night.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Maybe mention pedestrian')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' rights')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' but')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' also the')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' need')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' to be')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' cautious regardless')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Should')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' I mention')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' using')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' pedestrian')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' bridges')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' or under')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='passes as')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' alternatives?')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Yes, that')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta="'s a good")), + PartDeltaEvent( + index=0, + delta=ThinkingPartDelta( + content_delta="""\ + idea. + +""" + ), + ), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='Wait, but')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' in some countries')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', even')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' if you')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' have the right')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' of way,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' drivers might not')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' stop.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=" So it's")), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' better to always')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' ensure')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' the')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' vehicle')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' is stopping before')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' crossing. Maybe')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' emphasize')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' that even')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' if you')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' have the signal')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', check')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' that')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' cars are stopping')), + PartDeltaEvent( + index=0, + delta=ThinkingPartDelta( + content_delta="""\ +. + +Also\ +""" + ), + ), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', the importance')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' of not')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' assuming')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' that drivers can')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' see you.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Sometimes')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' drivers')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' are')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' distracted too')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='. So')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' being')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' proactive in')), + PartDeltaEvent( + index=0, + delta=ThinkingPartDelta( + content_delta="""\ + ensuring safety. + +""" + ), + ), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='Let')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' me check if')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' I missed')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' anything.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Maybe the')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' basic')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' steps are')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' covered')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', but adding')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' the')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' extra tips makes')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' it comprehensive')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='. Okay')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=', I think')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=" that's a")), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' solid structure')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='. Now,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' present it in')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' a clear,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' step-by-step')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' manner with')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' some')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' bullet')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' points or')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' numbered')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' list')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Make sure the')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' language is simple')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' and easy to')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' understand,')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' avoiding jargon.')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' Al')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta='right, time')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' to put it')), + PartDeltaEvent(index=0, delta=ThinkingPartDelta(content_delta=' all together.\n')), + PartStartEvent( + index=1, + part=TextPart( + content="""\ + + +""" + ), + ), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='Crossing the')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' street safely involves')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' careful')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' observation')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' and awareness.')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=" Here's")), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' a step')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='-by-step guide')), + PartDeltaEvent( + index=1, + delta=TextPartDelta( + content_delta="""\ +: + +###\ +""" + ), + ), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='Basic')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Steps**')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' **Find a')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Safe Spot')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='**:')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Use a **')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='crosswalk**')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' or pedestrian signal')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' if available.')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Avoid j')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='aywalking')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=', as it')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' in')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' many areas')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' and less')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' safe. \n')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' -')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' If no')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' crosswalk exists')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=', choose')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' a well')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='-lit area with')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' clear visibility in')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='2. **')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='Check Traffic Signals')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' - Wait')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' for the')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' "walk')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='" signal')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' or')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' green light')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' at intersections')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='. \n')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' - Watch')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' for count')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='down timers')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' to ensure you')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' have enough time')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='3. **')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='Look Both')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Ways**: \n')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' - **')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='Left-Right')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='-Left**:')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Glance left')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=', right')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=', and')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' left again (')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='or right')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='-left-right')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' in countries')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' where traffic drives')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' on the left')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=', like the')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' UK). \n')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' - Listen')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' for approaching')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' vehicles,')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' especially bikes')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' or quiet')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' electric')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='4. **')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='Ensure All')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Traffic')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Has')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Stopped**:')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' - Make')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' eye contact with')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' drivers if possible')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=',')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' and')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' wait')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' for vehicles')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' to come')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' to a')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' complete stop before')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' stepping')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' into')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' the road')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='.')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Watch for turning')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' vehicles,')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' even if you')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' have the right')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' of')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='5. **')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='Cross Prompt')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='ly and')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Saf')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='ely**: \n')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' - Walk')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' straight across')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='—')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' run or')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' stop')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' midway')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' - Stay inside')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' cross')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='walk')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' lines')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' if they')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent( + index=1, + delta=TextPartDelta( + content_delta="""\ +. + +6\ +""" + ), + ), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='. **Stay')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Alert Until')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' You')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Reach the Other')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Side**: \n')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' -')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Keep scanning')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' for traffic as')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' you cross')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='. Avoid')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' distractions like phones')), + PartDeltaEvent( + index=1, + delta=TextPartDelta( + content_delta="""\ + or headphones. + +""" + ), + ), + PartDeltaEvent( + index=1, + delta=TextPartDelta( + content_delta="""\ +--- + +""" + ), + ), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='### **Additional')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Tips**')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='At')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Night**:')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Wear reflective')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' clothing or carry')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' a flashlight')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' to improve')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' visibility. \n')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='- **With')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Kids')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' or')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Disabilities**: Hold')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' hands with')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' children,')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' and')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' use assistive')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' devices')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' (e.g')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='., white')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' canes).')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Seek')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' pedestrian bridges')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' or under')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='passes if')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' available. \n')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='- **Un')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='marked Roads')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='**: Cross')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' where')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' you')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' can see on')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='coming traffic clearly')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=', and never')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' assume drivers see')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' you. \n')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='- **')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='International Travel')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='**: Note')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' local traffic patterns')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' (e.g')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='., left')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='-side driving)')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' and pedestrian')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' customs')), + PartDeltaEvent( + index=1, + delta=TextPartDelta( + content_delta="""\ +. + +### **\ +""" + ), + ), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='Remember**:')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='Right')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' of Way ≠')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Inv')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='incibility**:')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' Even with')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' a')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' signal, double')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='-check that')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' cars')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' are stopping.')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='Distractions Kill')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='**: Stay')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' focused—')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='no texting')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' or scrolling while')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='By following these')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' steps,')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=IsStr())), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='ll minimize')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' risks and')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' cross')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' safely')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='!')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta=' 🚶')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='♂')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='️🚦')), + PartDeltaEvent(index=1, delta=TextPartDelta(content_delta='')), + ] + ) diff --git a/tests/models/test_cohere.py b/tests/models/test_cohere.py index 85f09daeb..f3cb2d86f 100644 --- a/tests/models/test_cohere.py +++ b/tests/models/test_cohere.py @@ -17,6 +17,7 @@ RetryPromptPart, SystemPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, UserPromptPart, @@ -24,7 +25,7 @@ from pydantic_ai.tools import RunContext from pydantic_ai.usage import Usage -from ..conftest import IsDatetime, IsNow, raise_if_exception, try_import +from ..conftest import IsDatetime, IsInstance, IsNow, raise_if_exception, try_import with try_import() as imports_successful: import cohere @@ -391,3 +392,113 @@ def simple_instructions(ctx: RunContext): ), ] ) + + +@pytest.mark.vcr() +async def test_cohere_model_thinking_part(allow_model_requests: None, co_api_key: str, openai_api_key: str): + with try_import() as imports_successful: + from pydantic_ai.models.openai import OpenAIResponsesModel, OpenAIResponsesModelSettings + from pydantic_ai.providers.openai import OpenAIProvider + + if not imports_successful(): # pragma: no cover + pytest.skip('OpenAI is not installed') + + openai_model = OpenAIResponsesModel('o3-mini', provider=OpenAIProvider(api_key=openai_api_key)) + co_model = CohereModel('command-r7b-12-2024', provider=CohereProvider(api_key=co_api_key)) + agent = Agent(openai_model) + + # We call OpenAI to get the thinking parts, because Google disabled the thoughts in the API. + # See https://github.com/pydantic/pydantic-ai/issues/793 for more details. + result = await agent.run( + 'How do I cross the street?', + model_settings=OpenAIResponsesModelSettings( + openai_reasoning_effort='high', openai_reasoning_summary='detailed' + ), + ) + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + IsInstance(TextPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + ], + model_name='o3-mini-2025-01-31', + timestamp=IsDatetime(), + ), + ] + ) + + result = await agent.run( + 'Considering the way to cross the street, analogously, how do I cross the river?', + model=co_model, + message_history=result.all_messages(), + ) + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + IsInstance(TextPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + ], + model_name='o3-mini-2025-01-31', + timestamp=IsDatetime(), + ), + ModelRequest( + parts=[ + UserPromptPart( + content='Considering the way to cross the street, analogously, how do I cross the river?', + timestamp=IsDatetime(), + ) + ] + ), + ModelResponse( + parts=[ + TextPart( + content="""\ +Crossing a river can be a different challenge compared to crossing a street, and the approach to safety and navigation will vary. Here are some considerations and steps to help you cross a river safely: + +1. **Determine the River's Characteristics:** + - **Width and Depth:** Measure or estimate the width of the river. Very wide rivers may require a boat or bridge for safe crossing. Also, assess the depth; shallow areas might be safe to wade through, while deeper sections may require a different method. + - **Current and Flow:** Understand the river's current. Strong currents can make swimming dangerous and may carry debris. Always check the flow rate and direction before attempting to cross. + - **Hazards:** Look for potential hazards like rocks, logs, or underwater obstacles that could cause injury or damage to equipment. + +2. **Choose a Safe Crossing Method:** + - **Fording:** If the river is shallow and the current is gentle, you might be able to ford the river. This involves walking through the water, often with the help of a sturdy stick or pole for balance and support. Always test the depth and current before attempting to ford. + - **Swimming:** Swimming across a river is a challenging and potentially dangerous option. It requires strong swimming skills, endurance, and knowledge of river currents. Always swim with a buddy and be aware of your surroundings. + - **Boat or Raft:** Using a boat, raft, or even an inflatable tube can be a safe and efficient way to cross. Ensure the boat is sturdy, properly equipped, and that you have the necessary safety gear, such as life jackets and a first-aid kit. + - **Bridge or Ferry:** If available, use a bridge or a ferry service. These are typically the safest and most reliable methods for crossing a river. + +3. **Prepare and Pack Essential Items:** + - **Life Jacket/Personal Floatation Device (PFD):** Always wear a life jacket or PFD when crossing a river, especially if swimming or using a boat. + - **First-Aid Kit:** Carry a basic first-aid kit to handle any minor injuries that might occur during the crossing. + - **Map and Compass:** Navigate the river and its surroundings with the help of a map and compass, especially if you're in an unfamiliar area. + - **Communication Device:** Have a means of communication, such as a satellite phone or a personal locator beacon, especially in remote areas. + - **Dry Clothing and Shelter:** Pack extra dry clothing and a waterproof shelter (like a tarp or tent) in case you get wet or need to wait out bad weather. + +4. **Follow River Safety Guidelines:** + - **Stay on Marked Paths:** If there are designated river paths or trails, use them. These routes are often designed to be safer and less prone to hazards. + - **Avoid Hazards:** Be cautious of slippery rocks, strong currents, and hidden underwater obstacles. Never swim or ford in areas with known dangers. + - **Group Safety:** If crossing with others, stay together. It's easier to keep an eye on each other and provide assistance if needed. + +5. **Be Prepared for Emergencies:** + - **Know Emergency Procedures:** Familiarize yourself with river rescue techniques and procedures. Learn how to signal for help and basic survival skills. + - **Carry Emergency Supplies:** Pack emergency supplies, including a whistle, a bright-colored cloth to signal, and a signal mirror (if available). + - **Leave a Plan:** Inform someone on the riverbank about your crossing plans, including your expected time of return. This person can raise the alarm if you don't return as scheduled. + +Remember, crossing a river can be a challenging and potentially dangerous endeavor. Always prioritize safety, and if in doubt, seek professional guidance or assistance from experienced river guides or local authorities. It's better to be over-prepared than caught off guard in a river crossing situation.\ +""" + ) + ], + model_name='command-r7b-12-2024', + timestamp=IsDatetime(), + ), + ] + ) diff --git a/tests/models/test_deepseek.py b/tests/models/test_deepseek.py new file mode 100644 index 000000000..648078329 --- /dev/null +++ b/tests/models/test_deepseek.py @@ -0,0 +1,36 @@ +from __future__ import annotations as _annotations + +import pytest +from inline_snapshot import snapshot + +from pydantic_ai import Agent +from pydantic_ai.messages import ModelRequest, ModelResponse, TextPart, ThinkingPart, UserPromptPart + +from ..conftest import IsDatetime, IsStr, try_import + +with try_import() as imports_successful: + from pydantic_ai.models.openai import OpenAIModel + from pydantic_ai.providers.deepseek import DeepSeekProvider + + +pytestmark = [ + pytest.mark.skipif(not imports_successful(), reason='openai not installed'), + pytest.mark.anyio, + pytest.mark.vcr, +] + + +async def test_deepseek_model_thinking_part(allow_model_requests: None, deepseek_api_key: str): + deepseek_model = OpenAIModel('deepseek-reasoner', provider=DeepSeekProvider(api_key=deepseek_api_key)) + agent = Agent(model=deepseek_model) + result = await agent.run('How do I cross the street?') + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ThinkingPart(content=IsStr()), TextPart(content=IsStr())], + model_name='deepseek-reasoner', + timestamp=IsDatetime(), + ), + ] + ) diff --git a/tests/models/test_gemini.py b/tests/models/test_gemini.py index ddf9a91bf..837dc1524 100644 --- a/tests/models/test_gemini.py +++ b/tests/models/test_gemini.py @@ -25,6 +25,7 @@ RetryPromptPart, SystemPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, UserPromptPart, @@ -50,7 +51,7 @@ from pydantic_ai.result import Usage from pydantic_ai.tools import ToolDefinition -from ..conftest import ClientWithHandler, IsDatetime, IsNow, IsStr, TestEnv +from ..conftest import ClientWithHandler, IsDatetime, IsInstance, IsNow, IsStr, TestEnv, try_import pytestmark = pytest.mark.anyio @@ -1066,3 +1067,117 @@ async def get_temperature(location: dict[str, CurrentLocation]) -> float: # pra assert result.output == snapshot( 'I need a location dictionary to use the `get_temperature` function. I cannot provide the temperature in Tokyo without more information.\n' ) + + +@pytest.mark.vcr() +async def test_gemini_model_thinking_part(allow_model_requests: None, gemini_api_key: str, openai_api_key: str): + with try_import() as imports_successful: + from pydantic_ai.models.openai import OpenAIResponsesModel, OpenAIResponsesModelSettings + from pydantic_ai.providers.openai import OpenAIProvider + + if not imports_successful(): # pragma: no cover + pytest.skip('OpenAI is not installed') + + openai_model = OpenAIResponsesModel('o3-mini', provider=OpenAIProvider(api_key=openai_api_key)) + gemini_model = GeminiModel('gemini-2.5-flash-preview-04-17', provider=GoogleGLAProvider(api_key=gemini_api_key)) + agent = Agent(openai_model) + + # We call OpenAI to get the thinking parts, because Google disabled the thoughts in the API. + # See https://github.com/pydantic/pydantic-ai/issues/793 for more details. + result = await agent.run( + 'How do I cross the street?', + model_settings=OpenAIResponsesModelSettings( + openai_reasoning_effort='high', openai_reasoning_summary='detailed' + ), + ) + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + IsInstance(TextPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + ], + model_name='o3-mini-2025-01-31', + timestamp=IsDatetime(), + ), + ] + ) + + result = await agent.run( + 'Considering the way to cross the street, analogously, how do I cross the river?', + model=gemini_model, + message_history=result.all_messages(), + model_settings=GeminiModelSettings( + gemini_thinking_config={'thinking_budget': 1024, 'include_thoughts': True}, + ), + ) + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + IsInstance(TextPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + ], + model_name='o3-mini-2025-01-31', + timestamp=IsDatetime(), + ), + ModelRequest( + parts=[ + UserPromptPart( + content='Considering the way to cross the street, analogously, how do I cross the river?', + timestamp=IsDatetime(), + ) + ] + ), + ModelResponse( + parts=[ + TextPart( + content="""\ +Okay, let's draw an analogy between crossing a street and crossing a river, applying the safety principles from the street crossing guide to the river environment. + +Think of the **river** as being like the **street** – a natural barrier you need to get across. The **hazards** on the river are different from vehicles, but they are still things that can harm you. + +Here's the analogous guide for crossing a river: + +1. **Before you approach the river:** + * Just as you use a sidewalk to get to the street's edge, use a trail or the riverbank to get to a spot where you can assess the river. + * If you're inexperienced with rivers or unsure about the conditions, try to have someone experienced accompany you. + +2. **When you're ready to cross:** + * Just as you look and listen for vehicles, carefully **assess the river conditions**. Look in all directions (upstream, downstream, across): + * How fast is the current moving? (Like checking vehicle speed). + * How deep does the water look? (Like judging the width and how much time you have). + * Are there obstacles in the water (rocks, logs)? (Like parked cars or road hazards). + * Is the bottom visible and does it look stable? (Like checking the road surface). + * Check upstream for potential hazards coming towards you (like debris). + * Listen to the river – the sound can tell you if the current is very strong or if there are rapids. + * Acknowledge the river's power – just as you make eye contact with drivers, respect that the river can be dangerous and doesn't care if you're trying to cross. + +3. **Use designated crossing areas whenever possible:** + * If there's a **bridge or a ferry**, use it. These are like the crosswalks and traffic signals – the safest, established ways to cross, often managing the "flow" (of water below, or people/boats on the river). + * If you must wade or swim, look for the safest possible **crossing point** – maybe a wider, shallower section, a known ford, or a spot with a less turbulent current. This is like choosing a crosswalk instead of crossing anywhere. + +4. **While crossing:** + * Just as you stay alert and avoid distractions, **focus completely on the crossing**. Don't be looking at your phone or distracted by conversation if you are actively navigating the water. + * Move with purpose, but carefully. If wading, maintain your balance against the current and watch your footing. If swimming, focus on your technique and direction. Stay aware of where you are relative to your intended path and the river's flow. + +5. **After crossing:** + * Once you've safely reached the other side, take a moment to ensure you are truly out of the main flow and on stable ground. Be aware of the riverbank conditions. + +**Analogous Takeaway:** + +Just as you wouldn't just run blindly into a busy street, you shouldn't just jump into a river without understanding its conditions and choosing the safest method and location to cross. Be cautious, assess the "traffic" (current, depth, obstacles), and use the available "infrastructure" (bridges, ferries, established crossing points) whenever possible.\ +""" + ) + ], + model_name='gemini-2.5-flash-preview-04-17', + timestamp=IsDatetime(), + ), + ] + ) diff --git a/tests/models/test_groq.py b/tests/models/test_groq.py index 7c170f147..7abf6ecc9 100644 --- a/tests/models/test_groq.py +++ b/tests/models/test_groq.py @@ -23,13 +23,14 @@ RetryPromptPart, SystemPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, UserPromptPart, ) from pydantic_ai.usage import Usage -from ..conftest import IsDatetime, IsNow, IsStr, raise_if_exception, try_import +from ..conftest import IsDatetime, IsInstance, IsNow, IsStr, raise_if_exception, try_import from .mock_async_stream import MockAsyncStream with try_import() as imports_successful: @@ -46,7 +47,7 @@ from groq.types.chat.chat_completion_message_tool_call import Function from groq.types.completion_usage import CompletionUsage - from pydantic_ai.models.groq import GroqModel + from pydantic_ai.models.groq import GroqModel, GroqModelSettings from pydantic_ai.providers.groq import GroqProvider # note: we use Union here so that casting works with Python 3.9 @@ -56,6 +57,7 @@ pytestmark = [ pytest.mark.skipif(not imports_successful(), reason='groq not installed'), pytest.mark.anyio, + pytest.mark.vcr, ] @@ -504,7 +506,6 @@ async def test_no_delta(allow_model_requests: None): assert result.is_complete -@pytest.mark.vcr() async def test_image_url_input(allow_model_requests: None, groq_api_key: str): m = GroqModel('llama-3.2-11b-vision-preview', provider=GroqProvider(api_key=groq_api_key)) agent = Agent(m) @@ -544,7 +545,6 @@ async def test_audio_as_binary_content_input(allow_model_requests: None, media_t await agent.run(['hello', BinaryContent(data=base64_content, media_type=media_type)]) -@pytest.mark.vcr() async def test_image_as_binary_content_input( allow_model_requests: None, groq_api_key: str, image_content: BinaryContent ) -> None: @@ -588,7 +588,6 @@ async def test_init_with_provider_string(): assert model.client is not None -@pytest.mark.vcr() async def test_groq_model_instructions(allow_model_requests: None, groq_api_key: str): m = GroqModel('llama-3.3-70b-versatile', provider=GroqProvider(api_key=groq_api_key)) agent = Agent(m, instructions='You are a helpful assistant.') @@ -607,3 +606,215 @@ async def test_groq_model_instructions(allow_model_requests: None, groq_api_key: ), ] ) + + +async def test_groq_model_thinking_part(allow_model_requests: None, groq_api_key: str): + m = GroqModel('deepseek-r1-distill-llama-70b', provider=GroqProvider(api_key=groq_api_key)) + settings = GroqModelSettings(groq_reasoning_format='raw') + agent = Agent(m, instructions='You are a chef.', model_settings=settings) + + result = await agent.run('I want a recipe to cook Uruguayan alfajores.') + assert result.all_messages() == snapshot( + [ + ModelRequest( + parts=[UserPromptPart(content='I want a recipe to cook Uruguayan alfajores.', timestamp=IsDatetime())], + instructions='You are a chef.', + ), + ModelResponse( + parts=[ + ThinkingPart(content=IsStr()), + TextPart( + content="""\ + + +To make Uruguayan alfajores, follow these organized steps for a delightful baking experience: + +### Ingredients: +- 2 cups all-purpose flour +- 1 cup cornstarch +- 1 tsp baking powder +- 1/2 tsp salt +- 1 cup unsalted butter, softened +- 1 cup powdered sugar +- 1 egg +- 1 tsp vanilla extract +- Dulce de leche (store-bought or homemade) +- Powdered sugar for coating + +### Instructions: + +1. **Preheat Oven:** + - Preheat your oven to 300°F (150°C). Line a baking sheet with parchment paper. + +2. **Prepare Dough:** + - In a bowl, whisk together flour, cornstarch, baking powder, and salt. + - In another bowl, cream butter and powdered sugar until smooth. Add egg and vanilla, mixing well. + - Gradually incorporate the dry ingredients into the wet mixture until a dough forms. Wrap and let rest for 30 minutes. + +3. **Roll and Cut:** + - Roll dough to 1/4 inch thickness. Cut into 2-inch circles using a cutter or glass. + +4. **Bake:** + - Place cookies on the prepared baking sheet, bake for 15-20 minutes until edges are lightly golden. Cool on the sheet for 5 minutes, then transfer to a wire rack to cool completely. + +5. **Assemble Alfajores:** + - Spread a layer of dulce de leche on one cookie half. Sandwich with another cookie. Handle gently to avoid breaking. + +6. **Coat with Powdered Sugar:** + - Roll each alfajor in powdered sugar, pressing gently to adhere. + +7. **Optional Chocolate Coating:** + - For a chocolate version, melt chocolate and dip alfajores, then chill to set. + +8. **Storage:** + - Store in an airtight container at room temperature for up to a week. Freeze for longer storage. + +### Tips: +- Ensure butter is softened for smooth creaming. +- Check cookies after 15 minutes to avoid over-browning. +- Allow cookies to cool completely before handling. +- Homemade dulce de leche can be made by heating condensed milk until thickened. + +Enjoy your traditional Uruguayan alfajores with a cup of coffee or tea!\ +""" + ), + ], + model_name='deepseek-r1-distill-llama-70b', + timestamp=IsDatetime(), + ), + ] + ) + + result = await agent.run( + 'Considering the Uruguayan recipe, how can I cook the Argentinian one?', + message_history=result.all_messages(), + model_settings=GroqModelSettings(groq_reasoning_format='parsed'), + ) + assert result.all_messages() == snapshot( + [ + ModelRequest( + parts=[UserPromptPart(content='I want a recipe to cook Uruguayan alfajores.', timestamp=IsDatetime())], + instructions='You are a chef.', + ), + ModelResponse( + parts=[IsInstance(ThinkingPart), IsInstance(TextPart)], + model_name='deepseek-r1-distill-llama-70b', + timestamp=IsDatetime(), + ), + ModelRequest( + parts=[ + UserPromptPart( + content='Considering the Uruguayan recipe, how can I cook the Argentinian one?', + timestamp=IsDatetime(), + ) + ], + instructions='You are a chef.', + ), + ModelResponse( + parts=[ + ThinkingPart( + content="""\ +Alright, so I want to make Argentinian alfajores after successfully making the Uruguayan ones. I know that both countries have their own versions of alfajores, but I'm not entirely sure how they differ. Maybe the ingredients or the preparation steps are slightly different? I should probably start by researching what makes Argentinian alfajores unique compared to the Uruguayan ones. + +First, I remember that in the Uruguayan recipe, the cookies were more delicate, and the filling was a generous amount of dulce de leche. The process involved making the dough from scratch, baking the cookies, and then assembling them with the filling and sometimes coating them in powdered sugar or chocolate. + +For Argentinian alfajores, I think the cookies might have a different texture—perhaps they're crunchier or have a different flavor profile. Maybe the type of flour used is different, or there's an addition like cocoa powder for a chocolate version. Also, the filling might have variations, like adding caramel or nuts to the dulce de leche. + +I should look up some authentic Argentinian recipes to see the differences. Maybe the method of making the dough is slightly different, or the baking time and temperature vary. I also wonder if Argentinian alfajores are typically coated in something else besides powdered sugar, like cinnamon or coconut flakes. + +Another thing to consider is the size and shape of the cookies. Uruguayan alfajores might be smaller and rounder, while Argentinian ones could be larger or have a different shape. I should also check if there are any additional steps, like toasting the cookies or adding a layer of meringue. + +I need to make sure I have all the necessary ingredients. If the Argentinian version requires something different, like a specific type of flour or a particular flavoring, I'll need to adjust my shopping list. Also, if the filling is different, I might need to prepare it in a different way or add extra ingredients. + +I should also think about the assembly process. Maybe Argentinian alfajores are sandwiched with more filling or have a different way of sealing the cookies together. Perhaps they're rolled in coconut after being filled, or there's a step involving dipping them in chocolate. + +It would be helpful to watch a video or read a detailed recipe from an Argentinian source to get a better understanding. That way, I can follow the traditional method and ensure that my alfajores turn out authentic. I should also consider any tips or tricks that Argentinian bakers use to make their alfajores special. + +Finally, I need to plan the timing. Making alfajores can be a bit time-consuming, especially if you're making the dulce de leche from scratch. I should allocate enough time for preparing the dough, baking the cookies, and assembling the alfajores. + +Overall, the key steps I think I'll need to follow are: + +1. Research authentic Argentinian alfajores recipes to identify unique ingredients and steps. +2. Adjust the ingredient list based on the differences from the Uruguayan version. +3. Prepare the dough according to the Argentinian method, which might involve different mixing techniques or additional ingredients. +4. Bake the cookies, possibly at a different temperature or for a different duration. +5. Prepare the filling, which might include variations like caramel or nuts. +6. Assemble the alfajores, possibly adding extra coatings or layers. +7. Allow the alfajores to set before serving, to ensure the flavors meld together. + +By carefully following these steps and paying attention to the unique aspects of Argentinian alfajores, I should be able to create a delicious and authentic batch that captures the essence of this traditional South American treat. +""" + ), + TextPart( + content="""\ +To create authentic Argentinian alfajores, follow these organized steps, which highlight the unique characteristics and differences from the Uruguayan version: + +### Ingredients: +- **For the Cookies:** + - 2 cups all-purpose flour + - 1/2 cup cornstarch + - 1/4 cup unsweetened cocoa powder (optional for chocolate version) + - 1 teaspoon baking powder + - 1/2 teaspoon salt + - 1 cup unsalted butter, softened + - 1 cup powdered sugar + - 1 egg + - 1 teaspoon vanilla extract + +- **For the Filling:** + - Dulce de leche (store-bought or homemade) + - Optional: caramel sauce, chopped nuts, or cinnamon for added flavor + +- **For Coating:** + - Powdered sugar + - Optional: cinnamon, shredded coconut, or melted chocolate + +### Instructions: + +1. **Prepare the Dough:** + - In a large bowl, whisk together the flour, cornstarch, cocoa powder (if using), baking powder, and salt. + - In another bowl, cream the softened butter and powdered sugar until smooth. Add the egg and vanilla extract, mixing well. + - Gradually incorporate the dry ingredients into the wet mixture until a dough forms. Wrap the dough in plastic wrap and let it rest for 30 minutes. + +2. **Roll and Cut the Cookies:** + - Roll the dough to about 1/4 inch thickness on a lightly floured surface. + - Use a round cookie cutter or the rim of a glass to cut out circles of dough. Argentinian alfajores are often slightly larger than their Uruguayan counterparts. + +3. **Bake the Cookies:** + - Preheat the oven to 300°F (150°C). Line a baking sheet with parchment paper. + - Place the cookie rounds on the prepared baking sheet, leaving about 1 inch of space between each cookie. + - Bake for 15-20 minutes, or until the edges are lightly golden. Allow the cookies to cool on the baking sheet for 5 minutes before transferring them to a wire rack to cool completely. + +4. **Prepare the Filling:** + - Use store-bought dulce de leche or make your own by heating sweetened condensed milk until thickened. + - Optional: Stir in caramel sauce or chopped nuts into the dulce de leche for added flavor. + +5. **Assemble the Alfajores:** + - Once the cookies are completely cool, spread a generous amount of dulce de leche on the flat side of one cookie. + - Sandwich with another cookie, pressing gently to adhere. For an extra touch, roll the edges in chopped nuts or shredded coconut. + +6. **Coat with Powdered Sugar or Chocolate:** + - Roll each alfajor in powdered sugar, pressing gently to ensure it adheres. + - Optional: Melt chocolate and dip the alfajores, then sprinkle with cinnamon or coconut before the chocolate sets. + +7. **Allow to Set:** + - Let the alfajores sit for about 30 minutes to allow the flavors to meld together. + +8. **Serve and Enjoy:** + - Serve with a cup of coffee or tea. Store any leftovers in an airtight container at room temperature for up to a week. + +### Tips: +- **Dough Handling:** Ensure the butter is softened for a smooth dough, and don't overwork the dough to maintain the cookies' tender texture. +- **Baking:** Keep an eye on the cookies after 15 minutes to prevent over-browning. +- **Filling Variations:** Experiment with different fillings like caramel or nuts to create unique flavor profiles. +- **Coating Options:** Try different coatings such as cinnamon or coconut for a varied texture and taste. + +By following these steps, you'll create authentic Argentinian alfajores that capture the rich flavors and traditions of this beloved South American treat.\ +""" + ), + ], + model_name='deepseek-r1-distill-llama-70b', + timestamp=IsDatetime(), + ), + ] + ) diff --git a/tests/models/test_mistral.py b/tests/models/test_mistral.py index 3a4981629..a0c5f099a 100644 --- a/tests/models/test_mistral.py +++ b/tests/models/test_mistral.py @@ -22,13 +22,14 @@ RetryPromptPart, SystemPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, UserPromptPart, VideoUrl, ) -from ..conftest import IsDatetime, IsNow, raise_if_exception, try_import +from ..conftest import IsDatetime, IsNow, IsStr, raise_if_exception, try_import from .mock_async_stream import MockAsyncStream with try_import() as imports_successful: @@ -53,14 +54,16 @@ from mistralai.types.basemodel import Unset as MistralUnset from pydantic_ai.models.mistral import MistralModel, MistralStreamedResponse + from pydantic_ai.models.openai import OpenAIResponsesModel, OpenAIResponsesModelSettings from pydantic_ai.providers.mistral import MistralProvider + from pydantic_ai.providers.openai import OpenAIProvider # note: we use Union here so that casting works with Python 3.9 MockChatCompletion = Union[MistralChatCompletionResponse, Exception] MockCompletionEvent = Union[MistralCompletionEvent, Exception] pytestmark = [ - pytest.mark.skipif(not imports_successful(), reason='mistral not installed'), + pytest.mark.skipif(not imports_successful(), reason='mistral or openai not installed'), pytest.mark.anyio, ] @@ -1862,3 +1865,64 @@ async def test_mistral_model_instructions(allow_model_requests: None, mistral_ap ), ] ) + + +@pytest.mark.vcr() +async def test_mistral_model_thinking_part(allow_model_requests: None, openai_api_key: str, mistral_api_key: str): + openai_model = OpenAIResponsesModel('o3-mini', provider=OpenAIProvider(api_key=openai_api_key)) + settings = OpenAIResponsesModelSettings(openai_reasoning_effort='high', openai_reasoning_summary='detailed') + agent = Agent(openai_model, model_settings=settings) + + result = await agent.run('How do I cross the street?') + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + TextPart(content=IsStr()), + ThinkingPart(content=IsStr(), signature='rs_68079ad7f0588191af64f067e7314d840493b22e4095129c'), + ThinkingPart(content=IsStr(), signature='rs_68079ad7f0588191af64f067e7314d840493b22e4095129c'), + ThinkingPart(content=IsStr(), signature='rs_68079ad7f0588191af64f067e7314d840493b22e4095129c'), + ThinkingPart(content=IsStr(), signature='rs_68079ad7f0588191af64f067e7314d840493b22e4095129c'), + ], + model_name='o3-mini-2025-01-31', + timestamp=IsDatetime(), + ), + ] + ) + + mistral_model = MistralModel('mistral-large-latest', provider=MistralProvider(api_key=mistral_api_key)) + result = await agent.run( + 'Considering the way to cross the street, analogously, how do I cross the river?', + model=mistral_model, + message_history=result.all_messages(), + ) + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + TextPart(content=IsStr()), + ThinkingPart(content=IsStr(), signature='rs_68079ad7f0588191af64f067e7314d840493b22e4095129c'), + ThinkingPart(content=IsStr(), signature='rs_68079ad7f0588191af64f067e7314d840493b22e4095129c'), + ThinkingPart(content=IsStr(), signature='rs_68079ad7f0588191af64f067e7314d840493b22e4095129c'), + ThinkingPart(content=IsStr(), signature='rs_68079ad7f0588191af64f067e7314d840493b22e4095129c'), + ], + model_name='o3-mini-2025-01-31', + timestamp=IsDatetime(), + ), + ModelRequest( + parts=[ + UserPromptPart( + content='Considering the way to cross the street, analogously, how do I cross the river?', + timestamp=IsDatetime(), + ) + ] + ), + ModelResponse( + parts=[TextPart(content=IsStr())], + model_name='mistral-large-latest', + timestamp=IsDatetime(), + ), + ] + ) diff --git a/tests/models/test_model_test.py b/tests/models/test_model_test.py index 40e573146..02242dc74 100644 --- a/tests/models/test_model_test.py +++ b/tests/models/test_model_test.py @@ -300,6 +300,6 @@ def test_max_items(): ) def test_different_content_input(content: AudioUrl | VideoUrl | ImageUrl | BinaryContent): agent = Agent() - result = agent.run_sync('x', model=TestModel(custom_output_text='custom')) + result = agent.run_sync(['x', content], model=TestModel(custom_output_text='custom')) assert result.output == snapshot('custom') assert result.usage() == snapshot(Usage(requests=1, request_tokens=51, response_tokens=1, total_tokens=52)) diff --git a/tests/models/test_openai.py b/tests/models/test_openai.py index 4f63e6ea2..c416d99cc 100644 --- a/tests/models/test_openai.py +++ b/tests/models/test_openai.py @@ -25,6 +25,7 @@ RetryPromptPart, SystemPromptPart, TextPart, + ThinkingPart, ToolCallPart, ToolReturnPart, UserPromptPart, @@ -34,7 +35,7 @@ from pydantic_ai.result import Usage from pydantic_ai.settings import ModelSettings -from ..conftest import IsDatetime, IsNow, IsStr, raise_if_exception, try_import +from ..conftest import IsDatetime, IsInstance, IsNow, IsStr, raise_if_exception, try_import from .mock_async_stream import MockAsyncStream with try_import() as imports_successful: @@ -54,6 +55,8 @@ from pydantic_ai.models.openai import ( OpenAIModel, OpenAIModelSettings, + OpenAIResponsesModel, + OpenAIResponsesModelSettings, OpenAISystemPromptRole, _OpenAIJsonSchema, # pyright: ignore[reportPrivateUsage] ) @@ -66,6 +69,7 @@ pytestmark = [ pytest.mark.skipif(not imports_successful(), reason='openai not installed'), pytest.mark.anyio, + pytest.mark.vcr, ] @@ -569,7 +573,6 @@ async def test_system_prompt_role( @pytest.mark.parametrize('system_prompt_role', ['system', 'developer']) -@pytest.mark.vcr async def test_openai_o1_mini_system_role( allow_model_requests: None, system_prompt_role: Literal['system', 'developer'], @@ -679,7 +682,6 @@ async def test_image_as_binary_content_input( assert result.output == snapshot('The fruit in the image is a kiwi.') -@pytest.mark.vcr() async def test_audio_as_binary_content_input( allow_model_requests: None, audio_content: BinaryContent, openai_api_key: str ): @@ -716,7 +718,6 @@ def test_model_status_error(allow_model_requests: None) -> None: assert str(exc_info.value) == snapshot("status_code: 500, model_name: gpt-4o, body: {'error': 'test error'}") -@pytest.mark.vcr() @pytest.mark.parametrize('model_name', ['o3-mini', 'gpt-4o-mini', 'gpt-4.5-preview']) async def test_max_completion_tokens(allow_model_requests: None, model_name: str, openai_api_key: str): m = OpenAIModel(model_name, provider=OpenAIProvider(api_key=openai_api_key)) @@ -726,7 +727,6 @@ async def test_max_completion_tokens(allow_model_requests: None, model_name: str assert result.output == IsStr() -@pytest.mark.vcr() async def test_multiple_agent_tool_calls(allow_model_requests: None, gemini_api_key: str, openai_api_key: str): gemini_model = GeminiModel('gemini-2.0-flash-exp', provider=GoogleGLAProvider(api_key=gemini_api_key)) openai_model = OpenAIModel('gpt-4o-mini', provider=OpenAIProvider(api_key=openai_api_key)) @@ -756,7 +756,6 @@ async def get_capital(country: str) -> str: assert result.output == snapshot('The capital of England is London.') -@pytest.mark.vcr() async def test_user_id(allow_model_requests: None, openai_api_key: str): # This test doesn't do anything, it's just here to ensure that calls with `user` don't cause errors, including type. # Since we use VCR, creating tests with an `httpx.Transport` is not possible. @@ -1261,7 +1260,6 @@ class MyModel(BaseModel): ) -@pytest.mark.vcr() async def test_openai_instructions(allow_model_requests: None, openai_api_key: str): m = OpenAIModel('gpt-4o', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(m, instructions='You are a helpful assistant.') @@ -1282,7 +1280,6 @@ async def test_openai_instructions(allow_model_requests: None, openai_api_key: s ) -@pytest.mark.vcr() async def test_openai_model_without_system_prompt(allow_model_requests: None, openai_api_key: str): m = OpenAIModel('o3-mini', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(m, system_prompt='You are a potato.') @@ -1292,7 +1289,6 @@ async def test_openai_model_without_system_prompt(allow_model_requests: None, op ) -@pytest.mark.vcr() async def test_openai_instructions_with_tool_calls_keep_instructions(allow_model_requests: None, openai_api_key: str): m = OpenAIModel('gpt-4.1-mini', provider=OpenAIProvider(api_key=openai_api_key)) agent = Agent(m, instructions='You are a helpful assistant.') @@ -1328,3 +1324,126 @@ async def get_temperature(city: str) -> float: ), ] ) + + +async def test_openai_responses_model_thinking_part(allow_model_requests: None, openai_api_key: str): + m = OpenAIResponsesModel('o3-mini', provider=OpenAIProvider(api_key=openai_api_key)) + settings = OpenAIResponsesModelSettings(openai_reasoning_effort='high', openai_reasoning_summary='detailed') + agent = Agent(m, model_settings=settings) + + result = await agent.run('How do I cross the street?') + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + TextPart(content=IsStr()), + ThinkingPart(content=IsStr(), signature='rs_68034841ab2881918a8c210e3d988b9208c845d2be9bcdd8'), + ThinkingPart(content=IsStr(), signature='rs_68034841ab2881918a8c210e3d988b9208c845d2be9bcdd8'), + ThinkingPart(content=IsStr(), signature='rs_68034841ab2881918a8c210e3d988b9208c845d2be9bcdd8'), + ThinkingPart(content=IsStr(), signature='rs_68034841ab2881918a8c210e3d988b9208c845d2be9bcdd8'), + ], + model_name='o3-mini-2025-01-31', + timestamp=IsDatetime(), + ), + ] + ) + + result = await agent.run( + 'Considering the way to cross the street, analogously, how do I cross the river?', + message_history=result.all_messages(), + ) + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + TextPart(content=IsStr()), + ThinkingPart(content=IsStr(), signature='rs_68034841ab2881918a8c210e3d988b9208c845d2be9bcdd8'), + ThinkingPart(content=IsStr(), signature='rs_68034841ab2881918a8c210e3d988b9208c845d2be9bcdd8'), + ThinkingPart(content=IsStr(), signature='rs_68034841ab2881918a8c210e3d988b9208c845d2be9bcdd8'), + ThinkingPart(content=IsStr(), signature='rs_68034841ab2881918a8c210e3d988b9208c845d2be9bcdd8'), + ], + model_name='o3-mini-2025-01-31', + timestamp=IsDatetime(), + ), + ModelRequest( + parts=[ + UserPromptPart( + content='Considering the way to cross the street, analogously, how do I cross the river?', + timestamp=IsDatetime(), + ) + ] + ), + ModelResponse( + parts=[ + TextPart(content=IsStr()), + ThinkingPart(content=IsStr(), signature='rs_68034858dc588191bc3a6801c23e728f08c845d2be9bcdd8'), + ThinkingPart(content=IsStr(), signature='rs_68034858dc588191bc3a6801c23e728f08c845d2be9bcdd8'), + ThinkingPart(content=IsStr(), signature='rs_68034858dc588191bc3a6801c23e728f08c845d2be9bcdd8'), + ], + model_name='o3-mini-2025-01-31', + timestamp=IsDatetime(), + ), + ] + ) + + +async def test_openai_model_thinking_part(allow_model_requests: None, openai_api_key: str): + provider = OpenAIProvider(api_key=openai_api_key) + responses_model = OpenAIResponsesModel('o3-mini', provider=provider) + settings = OpenAIResponsesModelSettings(openai_reasoning_effort='high', openai_reasoning_summary='detailed') + agent = Agent(responses_model, model_settings=settings) + + result = await agent.run('How do I cross the street?') + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + TextPart(content=IsStr()), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + ], + model_name='o3-mini-2025-01-31', + timestamp=IsDatetime(), + ), + ] + ) + + result = await agent.run( + 'Considering the way to cross the street, analogously, how do I cross the river?', + model=OpenAIModel('o3-mini', provider=provider), + message_history=result.all_messages(), + ) + assert result.all_messages() == snapshot( + [ + ModelRequest(parts=[UserPromptPart(content='How do I cross the street?', timestamp=IsDatetime())]), + ModelResponse( + parts=[ + TextPart(content=IsStr()), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + IsInstance(ThinkingPart), + ], + model_name='o3-mini-2025-01-31', + timestamp=IsDatetime(), + ), + ModelRequest( + parts=[ + UserPromptPart( + content='Considering the way to cross the street, analogously, how do I cross the river?', + timestamp=IsDatetime(), + ) + ] + ), + ModelResponse( + parts=[TextPart(content=IsStr())], + model_name='o3-mini-2025-01-31', + timestamp=IsDatetime(), + ), + ] + ) diff --git a/tests/models/test_openai_responses.py b/tests/models/test_openai_responses.py index 29f15efc7..7b9021dd9 100644 --- a/tests/models/test_openai_responses.py +++ b/tests/models/test_openai_responses.py @@ -123,7 +123,7 @@ async def test_openai_responses_reasoning_generate_summary(allow_model_requests: agent = Agent( model=model, model_settings=OpenAIResponsesModelSettings( - openai_reasoning_generate_summary='concise', + openai_reasoning_summary='concise', openai_truncation='auto', ), ) diff --git a/tests/test_thinking_part.py b/tests/test_thinking_part.py new file mode 100644 index 000000000..0ee54b4fa --- /dev/null +++ b/tests/test_thinking_part.py @@ -0,0 +1,28 @@ +from __future__ import annotations as _annotations + +import pytest + +from pydantic_ai._thinking_part import split_content_into_text_and_thinking +from pydantic_ai.messages import ModelResponsePart, TextPart, ThinkingPart + + +@pytest.mark.parametrize( + ('content', 'parts'), + [ + ('foo bar', [TextPart(content='foo bar')]), + ( + 'foo barthinking', + [TextPart(content='foo bar'), ThinkingPart(content='thinking')], + ), + ( + 'foo barthinkingbaz', + [TextPart(content='foo bar'), ThinkingPart(content='thinking'), TextPart(content='baz')], + ), + ( + 'foo barthinking', + [TextPart(content='foo bar'), TextPart(content='thinking')], + ), + ], +) +def test_split_content_into_text_and_thinking(content: str, parts: list[ModelResponsePart]): + assert split_content_into_text_and_thinking(content) == parts diff --git a/uv.lock b/uv.lock index ccf30d874..4e1a2616d 100644 --- a/uv.lock +++ b/uv.lock @@ -418,16 +418,16 @@ wheels = [ [[package]] name = "boto3" -version = "1.37.1" +version = "1.38.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/21/8c/c2af03daafaacea1db1823d23073facffa75818b61d376c3be77dd297ae8/boto3-1.37.1.tar.gz", hash = "sha256:96d18f7feb0c1fcb95f8837b74b6c8880e1b4e35ce5f8a8f8cb243a090c278ed", size = 111175 } +sdist = { url = "https://files.pythonhosted.org/packages/fc/6c/61664d66c05888fcb960e316a265a7f65ade54d9e5983cbded7d8945e0c2/boto3-1.38.2.tar.gz", hash = "sha256:53c8d44b231251fa9421dd13d968236d59fe2cf0421e077afedbf3821653fb3b", size = 111817 } wheels = [ - { url = "https://files.pythonhosted.org/packages/63/ec/e722c53c9dc41e8df094587c32e19409bace8b43b5eb31fe3536ca57a38b/boto3-1.37.1-py3-none-any.whl", hash = "sha256:4320441f904435a1b85e6ecb81793192e522c737cc9ed6566014e29f0a11cb22", size = 139338 }, + { url = "https://files.pythonhosted.org/packages/ec/21/78e7b892153bd4a3cd94204ad554180b12f07a2ff8b182b6c35e2e643d36/boto3-1.38.2-py3-none-any.whl", hash = "sha256:ef3237b169cd906a44a32c03b3229833d923c9e9733355b329ded2151f91ec0b", size = 139898 }, ] [[package]] @@ -451,7 +451,7 @@ bedrock-runtime = [ [[package]] name = "botocore" -version = "1.37.1" +version = "1.38.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, @@ -459,9 +459,9 @@ dependencies = [ { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "urllib3", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e5/01/3083bff25fd91193162298920cb093b9095609408416526d52b2826965b7/botocore-1.37.1.tar.gz", hash = "sha256:b194db8fb2a0ffba53568c364ae26166e7eec0445496b2ac86a6e142f3dd982f", size = 13578835 } +sdist = { url = "https://files.pythonhosted.org/packages/06/3a/0576ba7922b295f57835469263357ad64e483676c37731c4b5c66457d2dc/botocore-1.38.2.tar.gz", hash = "sha256:b688a9bd17211a1eaae3a6c965ba9f3973e5435efaaa4fa201f499d3467830e1", size = 13848402 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/20/352b2bf99f93ba18986615841786cbd0d38f7856bd49d4e154a540f04afe/botocore-1.37.1-py3-none-any.whl", hash = "sha256:c1db1bfc5d8c6b3b6d1ca6794f605294b4264e82a7e727b88e0fef9c2b9fbb9c", size = 13359164 }, + { url = "https://files.pythonhosted.org/packages/21/40/28512e643df1674c8560fb2ea5676bd46413173695423b567eca041a901c/botocore-1.38.2-py3-none-any.whl", hash = "sha256:5d9cffedb1c759a058b43793d16647ed44ec87072f98a1bd6cd673ac0ae6b81d", size = 13506508 }, ] [[package]] @@ -1214,7 +1214,7 @@ wheels = [ [[package]] name = "groq" -version = "0.18.0" +version = "0.22.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -1224,9 +1224,9 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/40/8c/e72c164474a88dfed6c7327ad53cb87ff11566b74b3a76d41dc7b94fc51c/groq-0.18.0.tar.gz", hash = "sha256:8e2ccfea406d68b3525af4b7c0e321fcb3d2a73fc60bb70b4156e6cd88c72f03", size = 117322 } +sdist = { url = "https://files.pythonhosted.org/packages/fd/59/7e03f5b12c097b7af48d5fe847a5bd00c90ccfc04b801c2ae68a043ddf1e/groq-0.22.0.tar.gz", hash = "sha256:9d090fbe4a051655faff649890d18aaacb3121393ad9d55399171fe081f1057b", size = 122956 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/6c/5a53d632b44ef7655ac8d9b34432e13160917f9307c94b1467efd34e336e/groq-0.18.0-py3-none-any.whl", hash = "sha256:81d5ac00057a45d8ce559d23ab5d3b3893011d1f12c35187ab35a9182d826ea6", size = 121911 }, + { url = "https://files.pythonhosted.org/packages/70/77/e6b60636f648922cc53144c36e1e7b77c9670539aab9e8b84a5fd1a53880/groq-0.22.0-py3-none-any.whl", hash = "sha256:f53d3966dff713aaa635671c2d075ebb932b0d48e3c4031ede9b84a2a6694c79", size = 126685 }, ] [[package]] @@ -2156,7 +2156,7 @@ wheels = [ [[package]] name = "openai" -version = "1.75.0" +version = "1.76.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -2168,9 +2168,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/99/b1/318f5d4c482f19c5fcbcde190801bfaaaec23413cda0b88a29f6897448ff/openai-1.75.0.tar.gz", hash = "sha256:fb3ea907efbdb1bcfd0c44507ad9c961afd7dce3147292b54505ecfd17be8fd1", size = 429492 } +sdist = { url = "https://files.pythonhosted.org/packages/84/51/817969ec969b73d8ddad085670ecd8a45ef1af1811d8c3b8a177ca4d1309/openai-1.76.0.tar.gz", hash = "sha256:fd2bfaf4608f48102d6b74f9e11c5ecaa058b60dad9c36e409c12477dfd91fb2", size = 434660 } wheels = [ - { url = "https://files.pythonhosted.org/packages/80/9a/f34f163294345f123673ed03e77c33dee2534f3ac1f9d18120384457304d/openai-1.75.0-py3-none-any.whl", hash = "sha256:fe6f932d2ded3b429ff67cc9ad118c71327db32eb9d32dd723de3acfca337125", size = 646972 }, + { url = "https://files.pythonhosted.org/packages/59/aa/84e02ab500ca871eb8f62784426963a1c7c17a72fea3c7f268af4bbaafa5/openai-1.76.0-py3-none-any.whl", hash = "sha256:a712b50e78cf78e6d7b2a8f69c4978243517c2c36999756673e07a14ce37dc0a", size = 661201 }, ] [[package]] @@ -2969,19 +2969,19 @@ dev = [ requires-dist = [ { name = "anthropic", marker = "extra == 'anthropic'", specifier = ">=0.49.0" }, { name = "argcomplete", marker = "extra == 'cli'", specifier = ">=3.5.0" }, - { name = "boto3", marker = "extra == 'bedrock'", specifier = ">=1.35.74" }, + { name = "boto3", marker = "extra == 'bedrock'", specifier = ">=1.37.24" }, { name = "cohere", marker = "sys_platform != 'emscripten' and extra == 'cohere'", specifier = ">=5.13.11" }, { name = "duckduckgo-search", marker = "extra == 'duckduckgo'", specifier = ">=7.0.0" }, { name = "eval-type-backport", specifier = ">=0.2.0" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "google-auth", marker = "extra == 'vertexai'", specifier = ">=2.36.0" }, { name = "griffe", specifier = ">=1.3.2" }, - { name = "groq", marker = "extra == 'groq'", specifier = ">=0.15.0" }, + { name = "groq", marker = "extra == 'groq'", specifier = ">=0.19.0" }, { name = "httpx", specifier = ">=0.27" }, { name = "logfire", marker = "extra == 'logfire'", specifier = ">=3.11.0" }, { name = "mcp", marker = "python_full_version >= '3.10' and extra == 'mcp'", specifier = ">=1.6.0" }, { name = "mistralai", marker = "extra == 'mistral'", specifier = ">=1.2.5" }, - { name = "openai", marker = "extra == 'openai'", specifier = ">=1.75.0" }, + { name = "openai", marker = "extra == 'openai'", specifier = ">=1.76.0" }, { name = "opentelemetry-api", specifier = ">=1.28.0" }, { name = "prompt-toolkit", marker = "extra == 'cli'", specifier = ">=3" }, { name = "pydantic", specifier = ">=2.10" }, @@ -3541,14 +3541,14 @@ wheels = [ [[package]] name = "s3transfer" -version = "0.11.2" +version = "0.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/62/45/2323b5928f86fd29f9afdcef4659f68fa73eaa5356912b774227f5cf46b5/s3transfer-0.11.2.tar.gz", hash = "sha256:3b39185cb72f5acc77db1a58b6e25b977f28d20496b6e58d6813d75f464d632f", size = 147885 } +sdist = { url = "https://files.pythonhosted.org/packages/fc/9e/73b14aed38ee1f62cd30ab93cd0072dec7fb01f3033d116875ae3e7b8b44/s3transfer-0.12.0.tar.gz", hash = "sha256:8ac58bc1989a3fdb7c7f3ee0918a66b160d038a147c7b5db1500930a607e9a1c", size = 149178 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/ac/e7dc469e49048dc57f62e0c555d2ee3117fa30813d2a1a2962cce3a2a82a/s3transfer-0.11.2-py3-none-any.whl", hash = "sha256:be6ecb39fadd986ef1701097771f87e4d2f821f27f6071c872143884d2950fbc", size = 84151 }, + { url = "https://files.pythonhosted.org/packages/89/64/d2b49620039b82688aeebd510bd62ff4cdcdb86cbf650cc72ae42c5254a3/s3transfer-0.12.0-py3-none-any.whl", hash = "sha256:35b314d7d82865756edab59f7baebc6b477189e6ab4c53050e28c1de4d9cce18", size = 84773 }, ] [[package]]