diff --git a/build_resources.yml b/build_resources.yml
index c61ccc7..f4c0942 100644
--- a/build_resources.yml
+++ b/build_resources.yml
@@ -5,6 +5,8 @@
- ui_src: resources
ui_files:
+ - build_asset_dialog
+ - build_template_dialog
- dialog
- open_publish_form
- widget_publish_history
diff --git a/hooks/tk-3dsmaxplus_actions.py b/hooks/tk-3dsmaxplus_actions.py
index 33bd40f..7903713 100644
--- a/hooks/tk-3dsmaxplus_actions.py
+++ b/hooks/tk-3dsmaxplus_actions.py
@@ -24,7 +24,7 @@ class MaxActions(HookBaseClass):
##############################################################################################################
# public interface - to be overridden by deriving classes
- def generate_actions(self, sg_publish_data, actions, ui_area):
+ def generate_actions(self, sg_publish_data, actions, ui_area, **kwargs):
"""
Returns a list of action instances for a particular publish.
This method is called each time a user clicks a publish somewhere in the UI.
@@ -101,7 +101,7 @@ def generate_actions(self, sg_publish_data, actions, ui_area):
return action_instances
- def execute_multiple_actions(self, actions):
+ def execute_multiple_actions(self, actions, **kwargs):
"""
Executes the specified action on a list of items.
@@ -132,7 +132,7 @@ def execute_multiple_actions(self, actions):
params = single_action["params"]
self.execute_action(name, params, sg_publish_data)
- def execute_action(self, name, params, sg_publish_data):
+ def execute_action(self, name, params, sg_publish_data, **kwargs):
"""
Execute a given action. The data sent to this be method will
represent one of the actions enumerated by the generate_actions method.
diff --git a/hooks/tk-desktop_actions.py b/hooks/tk-desktop_actions.py
new file mode 100644
index 0000000..12cdabe
--- /dev/null
+++ b/hooks/tk-desktop_actions.py
@@ -0,0 +1,301 @@
+# Copyright (c) 2026 Shotgun Software Inc.
+#
+# CONFIDENTIAL AND PROPRIETARY
+#
+# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit
+# Source Code License included in this distribution package. See LICENSE.
+# By accessing, using, copying or modifying this work you indicate your
+# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
+# not expressly granted therein are reserved by Shotgun Software Inc.
+
+"""
+Hook that loads defines all the available actions, broken down by publish type.
+"""
+
+import os
+from typing import Any
+
+import sgtk
+from sgtk import TankError
+
+HookBaseClass = sgtk.get_hook_baseclass()
+
+
+class DesktopActions(HookBaseClass):
+ """
+ Stub implementation of the shell actions, used for testing.
+ """
+
+ def generate_actions(
+ self,
+ sg_publish_data: dict,
+ actions: list,
+ ui_area: str,
+ **kwargs,
+ ) -> list:
+ """
+ Return a list of action instances for a particular publish.
+ This method is called each time a user clicks a publish somewhere in the UI.
+ The data returned from this hook will be used to populate the actions menu for a publish.
+
+ The mapping between Publish types and actions are kept in a different place
+ (in the configuration) so at the point when this hook is called, the loader app
+ has already established *which* actions are appropriate for this object.
+
+ The hook should return at least one action for each item passed in via the
+ actions parameter.
+
+ This method needs to return detailed data for those actions, in the form of a list
+ of dictionaries, each with name, params, caption and description keys.
+
+ Because you are operating on a particular publish, you may tailor the output
+ (caption, tooltip etc) to contain custom information suitable for this publish.
+
+ The ui_area parameter is a string and indicates where the publish is to be shown.
+ - If it will be shown in the main browsing area, "main" is passed.
+ - If it will be shown in the details area, "details" is passed.
+ - If it will be shown in the history area, "history" is passed.
+
+ Please note that it is perfectly possible to create more than one action "instance" for
+ an action! You can for example do scene introspection - if the action passed in
+ is "character_attachment" you may for example scan the scene, figure out all the nodes
+ where this object can be attached and return a list of action instances:
+ "attach to left hand", "attach to right hand" etc. In this case, when more than
+ one object is returned for an action, use the params key to pass additional
+ data into the run_action hook.
+
+ :param sg_publish_data: Shotgun data dictionary with all the standard publish fields.
+ :param actions: List of action strings which have been defined in the app configuration.
+ :param ui_area: String denoting the UI Area (see above).
+ :returns List of dictionaries, each with keys name, params, caption and description
+ """
+ app = self.parent
+ app.log_debug(
+ "Generate actions called for UI element %s. "
+ "Actions: %s. Publish Data: %s" % (ui_area, actions, sg_publish_data)
+ )
+
+ action_instances = []
+
+ enable_flowam = app.get_setting("enable_flowam", False)
+ if enable_flowam:
+ am_base_obj = kwargs.get("am_base_obj")
+ if not am_base_obj:
+ raise Exception(
+ "FlowAM is enabled but no Asset Management base object was passed to the action hook. "
+ "FlowAM specific actions will not be generated."
+ )
+
+ if "download" in actions and sg_publish_data.get("type") == "PublishedFile":
+ version_number = sg_publish_data.get("version_number")
+
+ if (
+ version_number is not None
+ and version_number != am_base_obj.DRAFT_VERSION_IDENTIFIER
+ ):
+ action_instances.append(
+ {
+ "name": "download",
+ "params": "Download 'params'",
+ "caption": "Download",
+ "description": "Downloads the published file to a user specified location.",
+ }
+ )
+
+ if "publish" in actions:
+ # Show publish action only for published files (not drafts)
+ # Drafts (version == -1) are not supported in generic workflow
+ version_number = sg_publish_data.get("version_number")
+
+ if version_number is not None and version_number >= 0:
+ action_instances.append(
+ {
+ "name": "publish",
+ "params": "Publish 'params'",
+ "caption": "Publish",
+ "description": "Publish a new revision of this generic asset.",
+ }
+ )
+
+ if "create_generic_asset" in actions:
+ action_instances.append(
+ {
+ "name": "create_generic_asset",
+ "params": "Create Generic Asset 'params'",
+ "caption": "Create Generic Asset",
+ "description": "Executes Create Generic Asset.",
+ }
+ )
+
+ if (
+ "reference_copy_link" in actions
+ and sg_publish_data.get(
+ "version_number", am_base_obj.DRAFT_VERSION_IDENTIFIER
+ )
+ > am_base_obj.DRAFT_VERSION_IDENTIFIER
+ ):
+ action_instances.append(
+ {
+ "name": "reference_copy_link",
+ "params": None,
+ "caption": "Copy Reference Link",
+ "description": "This will copy the reference as a string to the clipboard",
+ "multi_select": False,
+ }
+ )
+
+ return action_instances
+
+ def execute_multiple_actions(self, actions: list, **kwargs) -> None:
+ """
+ Executes the specified action on a list of items.
+
+ The default implementation dispatches each item from ``actions`` to
+ the ``execute_action`` method.
+
+ The ``actions`` is a list of dictionaries holding all the actions to execute.
+ Each entry will have the following values:
+
+ name: Name of the action to execute
+ sg_publish_data: Publish information coming from Shotgun
+ params: Parameters passed down from the generate_actions hook.
+
+ .. note::
+ This is the default entry point for the hook. It reuses the ``execute_action``
+ method for backward compatibility with hooks written for the previous
+ version of the loader.
+
+ .. note::
+ The hook will stop applying the actions on the selection if an error
+ is raised midway through.
+
+ :param list actions: Action dictionaries.
+ """
+ app = self.parent
+ app.log_info("Executing action '%s' on the selection")
+ # Helps to visually scope selections
+ # Execute each action.
+ for single_action in actions:
+ name = single_action["name"]
+ sg_publish_data = single_action["sg_publish_data"]
+ params = single_action["params"]
+ self.execute_action(name, params, sg_publish_data, **kwargs)
+
+ def execute_action(
+ self,
+ name: str,
+ params: Any,
+ sg_publish_data: dict,
+ **kwargs,
+ ) -> None:
+ """
+ Print out all actions. The data sent to this be method will
+ represent one of the actions enumerated by the generate_actions method.
+
+ :param name: Action name string representing one of the items returned by generate_actions.
+ :param params: Params data, as specified by generate_actions.
+ :param sg_publish_data: Shotgun data dictionary with all the standard publish fields.
+ :returns: No return value expected.
+ """
+ app = self.parent
+ app.log_debug(
+ "Execute action called for action %s. "
+ "Parameters: %s. Publish Data: %s" % (name, params, sg_publish_data)
+ )
+ am_base_obj = kwargs.get("am_base_obj")
+
+ if name == "create_generic_asset":
+ # Right click a task the left panel
+ self._launch_publisher(name, sg_publish_data)
+
+ elif name == "publish":
+ # action for a single PublishedFile
+ self._launch_publisher(name, sg_publish_data)
+
+ elif name == "reference_copy_link":
+ am_base_obj._create_reference_copy_link(sg_publish_data)
+
+ elif name == "download":
+ am_base_obj._download_asset_revision(sg_publish_data)
+
+ def _launch_publisher(self, action_name: str, sg_publish_data: dict) -> None:
+ """
+ Launches the publisher app in the context of the specified entity (task or project).
+ :param str action_name: Action name that triggered the publisher launch.
+ :param dict sg_publish_data: Shotgun data dictionary with all the standard publish fields.
+ """
+ engine = sgtk.platform.current_engine()
+
+ entity_type = sg_publish_data.get("type")
+ if not entity_type:
+ raise TankError("sg_publish_data missing 'type' field")
+
+ if entity_type == "Task":
+ # Case when action is triggered from a Task item
+ # as with "Create generic asset" action
+ task_id = sg_publish_data["id"]
+ entity_id = task_id
+ elif entity_type == "Project":
+ # Case when action is triggered from a Project item
+ # as with "Create generic asset" action
+ task_id = None # in this case task id is not relevant
+ entity_id = sg_publish_data["id"]
+ elif sg_publish_data.get("task"):
+ # Case when action is triggered from a PublishedFile item
+ # from task level, as with "Publish" action
+ task_id = sg_publish_data["task"]["id"]
+ entity_type = "Task"
+ entity_id = task_id
+ elif sg_publish_data.get("project"):
+ # Case when action is trigger from a PublishedFile item
+ # from project level, as with "Publish" action
+ task_id = None # in this case task id is not relevant
+ entity_type = "Project"
+ entity_id = sg_publish_data["project"]["id"]
+ else:
+ raise TankError(f"Invalid entity type for publish: {entity_type}.")
+
+ # Use different env var naming for project-level vs task-level contexts
+ if task_id is not None:
+ revision_id_env_var = f"TK_FLOWAM_REVISION_ID_{task_id}"
+ else:
+ # For project-level contexts, use project ID
+ project_id = entity_id
+ revision_id_env_var = f"TK_FLOWAM_REVISION_ID_PROJECT_{project_id}"
+
+ if action_name == "publish":
+ revision_id = sg_publish_data.get("sg_flow_revision_id")
+ os.environ[revision_id_env_var] = revision_id
+ else:
+ # Clear possible previously existing publish states from an unfinished publish
+ # (Finished publishes should clear this value)
+ if revision_id_env_var in os.environ:
+ os.environ.pop(revision_id_env_var)
+
+ # NOTE: the context should be either a Task or a Project
+ entity_ctx = engine.tank.context_from_entity(entity_type, entity_id)
+
+ # Get Publisher app from engine
+ publisher_app = engine.apps.get("tk-multi-publish2")
+ if not publisher_app:
+ # Publisher not configured
+ available_apps = list(engine.apps.keys())
+ raise TankError(
+ "Could not find Publisher app (tk-multi-publish2)!\n\n"
+ f"Available apps in current engine: {available_apps}\n\n"
+ "Please ensure tk-multi-publish2 is configured in:\n"
+ "env/includes/desktop/project.yml under 'desktop.project: apps:'\n\n"
+ )
+
+ try:
+ # Set context and launch Publisher using the pre-imported module
+ publisher_app._set_context(entity_ctx)
+
+ # For republish action, restrict publisher to single file mode
+ single_file_mode = action_name == "publish"
+ publisher_app.show_publish_dialog(single_file_mode=single_file_mode)
+ except Exception as e:
+ raise TankError(
+ f"Failed to launch Publisher: {e}\n\n"
+ f"The Publisher app was found but failed to start."
+ )
diff --git a/hooks/tk-flame_actions.py b/hooks/tk-flame_actions.py
index 8a6da4a..a75bcea 100644
--- a/hooks/tk-flame_actions.py
+++ b/hooks/tk-flame_actions.py
@@ -44,7 +44,7 @@ class FlameActionError(Exception):
class FlameActions(HookBaseClass):
##############################################################################################################
# public interface - to be overridden by deriving classes
- def generate_actions(self, sg_publish_data, actions, ui_area):
+ def generate_actions(self, sg_publish_data, actions, ui_area, **kwargs):
"""
Returns a list of action instances for a particular publish.
This method is called each time a user clicks a publish somewhere in the UI.
@@ -136,7 +136,7 @@ def generate_actions(self, sg_publish_data, actions, ui_area):
return action_instances
- def execute_multiple_actions(self, actions):
+ def execute_multiple_actions(self, actions, **kwargs):
"""
Executes the specified action on a list of items.
@@ -167,7 +167,7 @@ def execute_multiple_actions(self, actions):
params = single_action["params"]
self.execute_action(name, params, sg_publish_data)
- def execute_action(self, name, params, sg_publish_data):
+ def execute_action(self, name, params, sg_publish_data, **kwargs):
"""
Execute a given action. The data sent to this be method will
represent one of the actions enumerated by the generate_actions method.
diff --git a/hooks/tk-houdini_actions.py b/hooks/tk-houdini_actions.py
index 1b7f37c..0d9ec7a 100644
--- a/hooks/tk-houdini_actions.py
+++ b/hooks/tk-houdini_actions.py
@@ -14,6 +14,7 @@
import os
import re
+
import sgtk
HookBaseClass = sgtk.get_hook_baseclass()
@@ -24,7 +25,7 @@ class HoudiniActions(HookBaseClass):
##############################################################################################################
# public interface - to be overridden by deriving classes
- def generate_actions(self, sg_publish_data, actions, ui_area):
+ def generate_actions(self, sg_publish_data, actions, ui_area, **kwargs):
"""
Returns a list of action instances for a particular publish.
This method is called each time a user clicks a publish somewhere in the UI.
@@ -98,9 +99,107 @@ def generate_actions(self, sg_publish_data, actions, ui_area):
}
)
+ # -----------------------
+ # FlowAM specific actions
+ # -----------------------
+ enable_flowam = app.get_setting("enable_flowam", False)
+ if enable_flowam:
+ am_base_obj = kwargs.get("am_base_obj")
+ if not am_base_obj:
+ raise Exception(
+ "FlowAM is enabled but no Asset Management base object was passed to the action hook. "
+ "FlowAM specific actions will not be generated."
+ )
+
+ if "open" in actions and sg_publish_data.get("type") == "PublishedFile":
+ if (
+ am_base_obj._is_local_draft(sg_publish_data)
+ or sg_publish_data.get(
+ "version_number", am_base_obj.DRAFT_VERSION_IDENTIFIER
+ )
+ > am_base_obj.DRAFT_VERSION_IDENTIFIER
+ ):
+ action_instances.append(
+ {
+ "name": "open",
+ "params": None,
+ "caption": "Open",
+ "description": "This will open the item into the current scene.",
+ "multi_select": False,
+ }
+ )
+
+ if "download" in actions and sg_publish_data.get("type") == "PublishedFile":
+ version_number = sg_publish_data.get("version_number")
+
+ if (
+ version_number is not None
+ and version_number != am_base_obj.DRAFT_VERSION_IDENTIFIER
+ ):
+ action_instances.append(
+ {
+ "name": "download",
+ "params": "Download 'params'",
+ "caption": "Download",
+ "description": "Downloads the published file to a user specified location.",
+ }
+ )
+
+ if "discard_draft" in actions:
+ draft_id = sg_publish_data.get("sg_flow_revision_id")
+
+ if am_base_obj._is_local_draft(
+ sg_publish_data
+ ) and am_base_obj._is_new_asset(draft_id):
+ action_instances.append(
+ {
+ "name": "discard_draft",
+ "params": None,
+ "caption": "Discard Draft",
+ "description": "This will discard the local draft for this publish.",
+ }
+ )
+
+ if (
+ "reference_copy_link" in actions
+ and sg_publish_data.get(
+ "version_number", am_base_obj.DRAFT_VERSION_IDENTIFIER
+ )
+ != am_base_obj.DRAFT_VERSION_IDENTIFIER
+ ):
+ action_instances.append(
+ {
+ "name": "reference_copy_link",
+ "params": None,
+ "caption": "Copy Reference Link",
+ "description": "This will copy the reference as a string to the clipboard",
+ "multi_select": False,
+ }
+ )
+
+ if "build_new_scene" in actions:
+ action_instances.append(
+ {
+ "name": "build_new_scene",
+ "params": None,
+ "caption": "Build New Scene",
+ "description": "This will create a new scene in the current project.",
+ }
+ )
+
+ if "build_new_template" in actions:
+ action_instances.append(
+ {
+ "name": "build_new_template",
+ "params": None,
+ "caption": "Build New Template",
+ "description": "This will create a new template scene in the current project.",
+ }
+ )
+
return action_instances
- def execute_multiple_actions(self, actions):
+ def execute_multiple_actions(self, actions, **kwargs):
"""
Executes the specified action on a list of items.
@@ -129,9 +228,9 @@ def execute_multiple_actions(self, actions):
name = single_action["name"]
sg_publish_data = single_action["sg_publish_data"]
params = single_action["params"]
- self.execute_action(name, params, sg_publish_data)
+ self.execute_action(name, params, sg_publish_data, **kwargs)
- def execute_action(self, name, params, sg_publish_data):
+ def execute_action(self, name, params, sg_publish_data, **kwargs):
"""
Execute a given action. The data sent to this be method will
represent one of the actions enumerated by the generate_actions method.
@@ -147,6 +246,33 @@ def execute_action(self, name, params, sg_publish_data):
"Parameters: %s. Publish Data: %s" % (name, params, sg_publish_data)
)
+ # -----------------------
+ # FlowAM specific actions
+ # -----------------------
+ enable_flowam = app.get_setting("enable_flowam", False)
+ if enable_flowam:
+ am_base_obj = kwargs.get("am_base_obj")
+
+ if name == "open":
+ am_base_obj._do_open(sg_publish_data)
+
+ if name == "reference_copy_link":
+ am_base_obj._create_reference_copy_link(sg_publish_data)
+
+ if name == "discard_draft":
+ am_base_obj._discard_draft(sg_publish_data)
+
+ if name == "build_new_scene":
+ am_base_obj._build_new_scene(sg_publish_data)
+
+ if name == "build_new_template":
+ am_base_obj._build_new_template(sg_publish_data)
+
+ if name == "download":
+ am_base_obj._download_asset_revision(sg_publish_data)
+
+ return
+
# resolve path
path = self.get_publish_path(sg_publish_data)
diff --git a/hooks/tk-mari_actions.py b/hooks/tk-mari_actions.py
index 64f4475..accd0ba 100644
--- a/hooks/tk-mari_actions.py
+++ b/hooks/tk-mari_actions.py
@@ -25,7 +25,7 @@ class MariActions(HookBaseClass):
##############################################################################################################
# public interface - to be overridden by deriving classes
- def generate_actions(self, sg_publish_data, actions, ui_area):
+ def generate_actions(self, sg_publish_data, actions, ui_area, **kwargs):
"""
Returns a list of action instances for a particular publish.
This method is called each time a user clicks a publish somewhere in the UI.
@@ -108,7 +108,7 @@ def generate_actions(self, sg_publish_data, actions, ui_area):
return action_instances
- def execute_multiple_actions(self, actions):
+ def execute_multiple_actions(self, actions, **kwargs):
"""
Executes the specified action on a list of items.
@@ -139,7 +139,7 @@ def execute_multiple_actions(self, actions):
params = single_action["params"]
self.execute_action(name, params, sg_publish_data)
- def execute_action(self, name, params, sg_publish_data):
+ def execute_action(self, name, params, sg_publish_data, **kwargs):
"""
Execute a given action. The data sent to this be method will
represent one of the actions enumerated by the generate_actions method.
diff --git a/hooks/tk-maya_actions.py b/hooks/tk-maya_actions.py
index c3275dd..c7d9446 100644
--- a/hooks/tk-maya_actions.py
+++ b/hooks/tk-maya_actions.py
@@ -15,6 +15,7 @@
import glob
import os
import re
+
import maya.cmds as cmds
import maya.mel as mel
import sgtk
@@ -27,7 +28,7 @@ class MayaActions(HookBaseClass):
##############################################################################################################
# public interface - to be overridden by deriving classes
- def generate_actions(self, sg_publish_data, actions, ui_area):
+ def generate_actions(self, sg_publish_data, actions, ui_area, **kwargs):
"""
Returns a list of action instances for a particular publish.
This method is called each time a user clicks a publish somewhere in the UI.
@@ -125,9 +126,128 @@ def generate_actions(self, sg_publish_data, actions, ui_area):
}
)
+ # -----------------------
+ # FlowAM specific actions
+ # -----------------------
+ enable_flowam = app.get_setting("enable_flowam", False)
+ if enable_flowam:
+ am_base_obj = kwargs.get("am_base_obj")
+ if not am_base_obj:
+ raise Exception(
+ "FlowAM is enabled but no Asset Management base object was passed to the action hook. "
+ "FlowAM specific actions will not be generated."
+ )
+
+ if (
+ "open" in actions
+ and sg_publish_data.get("type") == "PublishedFile"
+ and (
+ am_base_obj._is_local_draft(sg_publish_data)
+ or sg_publish_data.get(
+ "version_number", am_base_obj.DRAFT_VERSION_IDENTIFIER
+ )
+ > am_base_obj.DRAFT_VERSION_IDENTIFIER
+ )
+ ):
+ action_instances.append(
+ {
+ "name": "open",
+ "params": None,
+ "caption": "Open",
+ "description": "This will open the item into the current scene.",
+ "multi_select": False,
+ }
+ )
+
+ if (
+ "download" in actions
+ and sg_publish_data.get("type") == "PublishedFile"
+ and (
+ sg_publish_data.get("version_number") is not None
+ and sg_publish_data.get("version_number")
+ != am_base_obj.DRAFT_VERSION_IDENTIFIER
+ )
+ ):
+ action_instances.append(
+ {
+ "name": "download",
+ "params": "Download 'params'",
+ "caption": "Download",
+ "description": "Downloads the published file to a user specified location.",
+ }
+ )
+
+ if "discard_draft" in actions:
+ draft_id = sg_publish_data.get("sg_flow_revision_id")
+
+ if am_base_obj._is_local_draft(
+ sg_publish_data
+ ) and am_base_obj._is_new_asset(draft_id):
+ action_instances.append(
+ {
+ "name": "discard_draft",
+ "params": None,
+ "caption": "Discard Draft",
+ "description": "This will discard the local draft for this publish.",
+ }
+ )
+
+ if (
+ "reference_am" in actions
+ and sg_publish_data.get(
+ "version_number", am_base_obj.DRAFT_VERSION_IDENTIFIER
+ )
+ != am_base_obj.DRAFT_VERSION_IDENTIFIER
+ ):
+ action_instances.append(
+ {
+ "name": "reference_am",
+ "params": None,
+ "caption": "Reference",
+ "description": "This will load the item into the current scene as a reference",
+ }
+ )
+
+ if (
+ "reference_copy_link" in actions
+ and sg_publish_data.get(
+ "version_number", am_base_obj.DRAFT_VERSION_IDENTIFIER
+ )
+ != am_base_obj.DRAFT_VERSION_IDENTIFIER
+ ):
+ action_instances.append(
+ {
+ "name": "reference_copy_link",
+ "params": None,
+ "caption": "Copy Reference Link",
+ "description": "This will copy the reference as a string to the clipboard",
+ "multi_select": False,
+ }
+ )
+
+ if "build_new_scene" in actions:
+ action_instances.append(
+ {
+ "name": "build_new_scene",
+ "params": None,
+ "caption": "Build New Scene",
+ "description": "This will create a new scene in the current project.",
+ }
+ )
+
+ if "build_new_template" in actions:
+ action_instances.append(
+ {
+ "name": "build_new_template",
+ "params": None,
+ "caption": "Build New Template",
+ "description": "This will create a new template scene in the current project.",
+ }
+ )
+
return action_instances
- def execute_multiple_actions(self, actions):
+ def execute_multiple_actions(self, actions, **kwargs):
"""
Executes the specified action on a list of items.
@@ -156,9 +276,9 @@ def execute_multiple_actions(self, actions):
name = single_action["name"]
sg_publish_data = single_action["sg_publish_data"]
params = single_action["params"]
- self.execute_action(name, params, sg_publish_data)
+ self.execute_action(name, params, sg_publish_data, **kwargs)
- def execute_action(self, name, params, sg_publish_data):
+ def execute_action(self, name, params, sg_publish_data, **kwargs):
"""
Execute a given action. The data sent to this be method will
represent one of the actions enumerated by the generate_actions method.
@@ -174,6 +294,36 @@ def execute_action(self, name, params, sg_publish_data):
"Parameters: %s. Publish Data: %s" % (name, params, sg_publish_data)
)
+ # -----------------------
+ # FlowAM specific actions
+ # -----------------------
+ enable_flowam = app.get_setting("enable_flowam", False)
+ if enable_flowam:
+ am_base_obj = kwargs.get("am_base_obj")
+
+ if name == "reference_am":
+ am_base_obj._create_reference_am(sg_publish_data)
+
+ if name == "reference_copy_link":
+ am_base_obj._create_reference_copy_link(sg_publish_data)
+
+ if name == "open":
+ am_base_obj._do_open(sg_publish_data)
+
+ if name == "discard_draft":
+ am_base_obj._discard_draft(sg_publish_data)
+
+ if name == "build_new_scene":
+ am_base_obj._build_new_scene(sg_publish_data)
+
+ if name == "build_new_template":
+ am_base_obj._build_new_template(sg_publish_data)
+
+ if name == "download":
+ am_base_obj._download_asset_revision(sg_publish_data)
+
+ return
+
path = self.get_publish_path(sg_publish_data)
if name == "reference":
diff --git a/hooks/tk-motionbuilder_actions.py b/hooks/tk-motionbuilder_actions.py
index 990cec5..da28e65 100644
--- a/hooks/tk-motionbuilder_actions.py
+++ b/hooks/tk-motionbuilder_actions.py
@@ -24,7 +24,7 @@ class MotionbuilderActions(HookBaseClass):
##############################################################################################################
# public interface - to be overridden by deriving classes
- def generate_actions(self, sg_publish_data, actions, ui_area):
+ def generate_actions(self, sg_publish_data, actions, ui_area, **kwargs):
"""
Returns a list of action instances for a particular publish.
This method is called each time a user clicks a publish somewhere in the UI.
@@ -81,7 +81,7 @@ def generate_actions(self, sg_publish_data, actions, ui_area):
return action_instances
- def execute_multiple_actions(self, actions):
+ def execute_multiple_actions(self, actions, **kwargs):
"""
Executes the specified action on a list of items.
@@ -112,7 +112,7 @@ def execute_multiple_actions(self, actions):
params = single_action["params"]
self.execute_action(name, params, sg_publish_data)
- def execute_action(self, name, params, sg_publish_data):
+ def execute_action(self, name, params, sg_publish_data, **kwargs):
"""
Execute a given action. The data sent to this be method will
represent one of the actions enumerated by the generate_actions method.
diff --git a/hooks/tk-nuke_actions.py b/hooks/tk-nuke_actions.py
index 06d5128..b3d078b 100644
--- a/hooks/tk-nuke_actions.py
+++ b/hooks/tk-nuke_actions.py
@@ -12,9 +12,9 @@
Hook that loads defines all the available actions, broken down by publish type.
"""
+import glob
import os
import re
-import glob
import sys
import sgtk
@@ -27,7 +27,7 @@ class NukeActions(HookBaseClass):
##############################################################################################################
# public interface - to be overridden by deriving classes
- def generate_actions(self, sg_publish_data, actions, ui_area):
+ def generate_actions(self, sg_publish_data, actions, ui_area, **kwargs):
"""
Returns a list of action instances for a particular publish.
This method is called each time a user clicks a publish somewhere in the UI.
@@ -112,9 +112,102 @@ def generate_actions(self, sg_publish_data, actions, ui_area):
}
)
+ # -----------------------
+ # FlowAM specific actions
+ # -----------------------
+ enable_flowam = app.get_setting("enable_flowam", False)
+ if enable_flowam:
+ am_base_obj = kwargs.get("am_base_obj")
+ if not am_base_obj:
+ raise Exception(
+ "FlowAM is enabled but no Asset Management base object was passed to the action hook. "
+ "FlowAM specific actions will not be generated."
+ )
+
+ if "build_new_script" in actions:
+ action_instances.append(
+ {
+ "name": "build_new_script",
+ "params": None,
+ "caption": "Build New Script",
+ "description": "This will create a new script in the current project.",
+ }
+ )
+ if "build_new_template" in actions:
+ action_instances.append(
+ {
+ "name": "build_new_template",
+ "params": None,
+ "caption": "Build New Template",
+ "description": "This will create a new template script in the current project.",
+ }
+ )
+ if "open" in actions and sg_publish_data.get("type") == "PublishedFile":
+ # Show open action for:
+ # 1. Local drafts (version_number == -1 and is_local_draft)
+ # 2. Published revisions (version_number > -1)
+ if (
+ am_base_obj._is_local_draft(sg_publish_data)
+ or sg_publish_data.get(
+ "version_number", am_base_obj.DRAFT_VERSION_IDENTIFIER
+ )
+ > am_base_obj.DRAFT_VERSION_IDENTIFIER
+ ):
+ action_instances.append(
+ {
+ "name": "open",
+ "params": None,
+ "caption": "Open",
+ "description": "This will open the item into the current script.",
+ }
+ )
+
+ if "discard_draft" in actions and am_base_obj._is_local_draft(
+ sg_publish_data
+ ):
+ action_instances.append(
+ {
+ "name": "discard_draft",
+ "params": None,
+ "caption": "Discard Draft",
+ "description": "This will discard the local draft.",
+ }
+ )
+ if (
+ "reference_copy_link" in actions
+ and sg_publish_data.get(
+ "version_number", am_base_obj.DRAFT_VERSION_IDENTIFIER
+ )
+ != am_base_obj.DRAFT_VERSION_IDENTIFIER
+ ):
+ action_instances.append(
+ {
+ "name": "reference_copy_link",
+ "params": None,
+ "caption": "Copy Reference Link",
+ "description": "This will copy the reference link as a string to the clipboard.",
+ "multi_select": False,
+ }
+ )
+ if (
+ "create_read_node" in actions
+ and sg_publish_data.get(
+ "version_number", am_base_obj.DRAFT_VERSION_IDENTIFIER
+ )
+ != am_base_obj.DRAFT_VERSION_IDENTIFIER
+ ):
+ action_instances.append(
+ {
+ "name": "create_read_node",
+ "params": None,
+ "caption": "Create Read Node",
+ "description": "This will load the item into the current script as a new Read node.",
+ }
+ )
+
return action_instances
- def execute_multiple_actions(self, actions):
+ def execute_multiple_actions(self, actions, **kwargs):
"""
Executes the specified action on a list of items.
@@ -143,9 +236,9 @@ def execute_multiple_actions(self, actions):
name = single_action["name"]
sg_publish_data = single_action["sg_publish_data"]
params = single_action["params"]
- self.execute_action(name, params, sg_publish_data)
+ self.execute_action(name, params, sg_publish_data, **kwargs)
- def execute_action(self, name, params, sg_publish_data):
+ def execute_action(self, name, params, sg_publish_data, **kwargs):
"""
Execute a given action. The data sent to this be method will
represent one of the actions enumerated by the generate_actions method.
@@ -162,6 +255,33 @@ def execute_action(self, name, params, sg_publish_data):
"Parameters: %s. Publish Data: %s" % (name, params, sg_publish_data)
)
+ # -----------------------
+ # FlowAM specific actions
+ # -----------------------
+ use_medm_data = app.get_setting("use_medm_data", False)
+ if use_medm_data:
+ am_base_obj = kwargs.get("am_base_obj")
+
+ if name == "build_new_script":
+ am_base_obj._build_new_scene(sg_publish_data)
+
+ if name == "build_new_template":
+ am_base_obj._build_new_template(sg_publish_data)
+
+ if name == "open":
+ am_base_obj._do_open(sg_publish_data)
+
+ if name == "discard_draft":
+ am_base_obj._discard_draft(sg_publish_data)
+
+ if name == "reference_copy_link":
+ am_base_obj._create_reference_copy_link(sg_publish_data)
+
+ if name == "create_read_node":
+ am_base_obj._create_reference(sg_publish_data)
+
+ return
+
# resolve path - forward slashes on all platforms in Nuke
path = self.get_publish_path(sg_publish_data).replace(os.path.sep, "/")
@@ -197,11 +317,7 @@ def _import_clip(self, path, sg_publish_data):
)
import hiero
- from hiero.core import (
- BinItem,
- MediaSource,
- Clip,
- )
+ from hiero.core import BinItem, Clip, MediaSource
if not hiero.core.projects():
raise Exception("An active project must exist to import clips into.")
diff --git a/hooks/tk-photoshop_actions.py b/hooks/tk-photoshop_actions.py
index c36a361..328e060 100644
--- a/hooks/tk-photoshop_actions.py
+++ b/hooks/tk-photoshop_actions.py
@@ -34,7 +34,7 @@ class PhotoshopActions(HookBaseClass):
##############################################################################################################
# public interface - to be overridden by deriving classes
- def generate_actions(self, sg_publish_data, actions, ui_area):
+ def generate_actions(self, sg_publish_data, actions, ui_area, **kwargs):
"""
Returns a list of action instances for a particular publish.
This method is called each time a user clicks a publish somewhere in the UI.
@@ -101,7 +101,7 @@ def generate_actions(self, sg_publish_data, actions, ui_area):
return action_instances
- def execute_multiple_actions(self, actions):
+ def execute_multiple_actions(self, actions, **kwargs):
"""
Executes the specified action on a list of items.
@@ -132,7 +132,7 @@ def execute_multiple_actions(self, actions):
params = single_action["params"]
self.execute_action(name, params, sg_publish_data)
- def execute_action(self, name, params, sg_publish_data):
+ def execute_action(self, name, params, sg_publish_data, **kwargs):
"""
Execute a given action. The data sent to this be method will
represent one of the actions enumerated by the generate_actions method.
diff --git a/hooks/tk-photoshopcc_actions.py b/hooks/tk-photoshopcc_actions.py
index c3725d6..36c4fe8 100644
--- a/hooks/tk-photoshopcc_actions.py
+++ b/hooks/tk-photoshopcc_actions.py
@@ -29,7 +29,7 @@ class PhotoshopActions(HookBaseClass):
##############################################################################################################
# public interface - to be overridden by deriving classes
- def generate_actions(self, sg_publish_data, actions, ui_area):
+ def generate_actions(self, sg_publish_data, actions, ui_area, **kwargs):
"""
Returns a list of action instances for a particular publish.
This method is called each time a user clicks a publish somewhere in the UI.
@@ -96,7 +96,7 @@ def generate_actions(self, sg_publish_data, actions, ui_area):
return action_instances
- def execute_multiple_actions(self, actions):
+ def execute_multiple_actions(self, actions, **kwargs):
"""
Executes the specified action on a list of items.
@@ -129,7 +129,7 @@ def execute_multiple_actions(self, actions):
params = single_action["params"]
self.execute_action(name, params, sg_publish_data)
- def execute_action(self, name, params, sg_publish_data):
+ def execute_action(self, name, params, sg_publish_data, **kwargs):
"""
Execute a given action. The data sent to this be method will
represent one of the actions enumerated by the generate_actions method.
diff --git a/hooks/tk-shell_actions.py b/hooks/tk-shell_actions.py
index 0471a04..dca3a5d 100644
--- a/hooks/tk-shell_actions.py
+++ b/hooks/tk-shell_actions.py
@@ -23,7 +23,7 @@ class ShellActions(HookBaseClass):
Stub implementation of the shell actions, used for testing.
"""
- def generate_actions(self, sg_publish_data, actions, ui_area):
+ def generate_actions(self, sg_publish_data, actions, ui_area, **kwargs):
"""
Return a list of action instances for a particular publish.
This method is called each time a user clicks a publish somewhere in the UI.
@@ -111,7 +111,7 @@ def generate_actions(self, sg_publish_data, actions, ui_area):
)
return action_instances
- def execute_multiple_actions(self, actions):
+ def execute_multiple_actions(self, actions, **kwargs):
"""
Executes the specified action on a list of items.
@@ -146,7 +146,7 @@ def execute_multiple_actions(self, actions):
params = single_action["params"]
self.execute_action(name, params, sg_publish_data)
- def execute_action(self, name, params, sg_publish_data):
+ def execute_action(self, name, params, sg_publish_data, **kwargs):
"""
Print out all actions. The data sent to this be method will
represent one of the actions enumerated by the generate_actions method.
diff --git a/info.yml b/info.yml
index 5cf316b..6e530f5 100644
--- a/info.yml
+++ b/info.yml
@@ -33,6 +33,14 @@ configuration:
Published File Types). The legacy Published File Type filter widget
cannot be used in combination with the Filter menu.
+ enable_flowam:
+ type: bool
+ default_value: false
+ description: Set to True to use Flow Asset Management data instead of Shotgun
+ data. When enabled, the loader fetches publish data from the Flow Asset
+ Management system. Requires tk-framework-flowam to be configured in the
+ environment.
+
# hooks
actions_hook:
type: hook
@@ -98,6 +106,39 @@ configuration:
default_value_tk-flame:
Shot: [load_batch, create_batch]
+ entity_fields_middle_panel_list:
+ type: dict
+ description: "Additional fields to display for each entity type in the middle panel
+ list view, beyond the default fields that are already shown. Keys are
+ entity types (e.g. 'PublishedFile', 'Shot', 'Asset') and values are
+ lists of field names to display."
+ default_value: {}
+ allows_empty: true
+
+ entity_fields_middle_panel_thumbnail:
+ type: dict
+ description: "Additional fields to display for each entity type in the middle panel
+ thumbnail view, beyond the default fields that are already shown. Keys
+ are entity types and values are lists of field names to display."
+ default_value: {}
+ allows_empty: true
+
+ entity_fields_detail_panel:
+ type: dict
+ description: "Fields to display for each entity type in detail panel view. Keys are
+ entity types (e.g. 'PublishedFile', 'Shot', 'Asset') and values are
+ lists of field names to display."
+ default_value: {}
+ allows_empty: true
+
+ flow_am_internal_fields:
+ type: dict
+ description: "Extra Flow AM fields loaded for internal logic or workflow purposes
+ (not for display). Available during model initialisation and accessible
+ throughout the app, but not shown in the UI."
+ default_value: {}
+ allows_empty: true
+
entities:
default_value:
- caption: Project
@@ -166,3 +207,5 @@ documentation_url: "https://help.autodesk.com/view/SGDEV/ENU/?guid=SG_Supervisor
frameworks:
- {"name": "tk-framework-shotgunutils", "version": "v5.x.x", "minimum_version": "v5.8.6"}
- {"name": "tk-framework-qtwidgets", "version": "v2.x.x", "minimum_version": "v2.10.6"}
+ # TODO: Remove the following line after SG-43459.
+ - {"name": "tk-framework-flowam", "version": "v1.x.x"}
diff --git a/python/tk_multi_loader/__init__.py b/python/tk_multi_loader/__init__.py
index d5e0288..c6abd81 100644
--- a/python/tk_multi_loader/__init__.py
+++ b/python/tk_multi_loader/__init__.py
@@ -8,17 +8,71 @@
# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
# not expressly granted therein are reserved by Shotgun Software Inc.
-from .api import LoaderManager
-from .open_publish_form import open_publish_browser
+from .api import LoaderManager # noqa: F401
+from .open_publish_form import open_publish_browser # noqa: F401
+
+import sys
import sgtk
from sgtk.platform.qt import QtCore, QtGui
-from .ui import resources_rc
+from .ui import resources_rc # noqa: F401
help_screen = sgtk.platform.import_framework("tk-framework-qtwidgets", "help_screen")
+def _clear_stay_on_top(win):
+ """
+ Clear WindowStaysOnTopHint so the loader doesn't stay on top of other apps or dialogs.
+
+ Nuke-specific bug: Tested across Maya, Houdini, and Nuke - confirmed this only
+ affects Nuke. Window flags comparison via hex(int(win.windowFlags())):
+ - Nuke: 0x8013003 (includes Qt.WindowStaysOnTopHint)
+ - Maya: 0x8003003 (normal flags)
+
+ In Nuke, Qt reports StaysOnTop = False but the window remains on top because
+ Qt injects WS_EX_TOPMOST at the OS level without reflecting it in its own flag
+ API (https://qt-project.atlassian.net/browse/QTBUG-36181). On Windows we must clear it directly via SetWindowPos.
+
+ The extra flags (SWP_NOMOVE, SWP_NOSIZE, SWP_NOACTIVATE) prevent accidental
+ window movement or resizing during the operation.
+ """
+ if win is None or not win.isWidgetType():
+ return
+
+ if sys.platform == "win32":
+ try:
+ import ctypes
+
+ # Verify WS_EX_TOPMOST is actually set at OS level before touching anything
+ GWL_EXSTYLE = -20
+ WS_EX_TOPMOST = 0x00000008
+ hwnd = int(win.winId())
+ if not hwnd:
+ return
+
+ exstyle = ctypes.windll.user32.GetWindowLongW(hwnd, GWL_EXSTYLE)
+ if not (exstyle & WS_EX_TOPMOST):
+ return # Already not topmost, nothing to do
+
+ # SetWindowPos with HWND_NOTOPMOST clears WS_EX_TOPMOST at the Win32 level
+ HWND_NOTOPMOST = -2
+ SWP_NOMOVE = 0x0002
+ SWP_NOSIZE = 0x0001
+ SWP_NOACTIVATE = 0x0010
+ ctypes.windll.user32.SetWindowPos(
+ hwnd,
+ ctypes.c_void_p(HWND_NOTOPMOST),
+ 0,
+ 0,
+ 0,
+ 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE,
+ )
+ except Exception:
+ pass
+
+
def show_dialog(app):
"""
Show the main loader dialog
@@ -44,9 +98,6 @@ def show_dialog(app):
ui_title = app.get_setting("title_name")
w = app.engine.show_dialog(ui_title, app, AppDialog, action_manager)
- # Keep pointer to dialog so as to be able to hide/show it in actions
- engine_name = app.engine.instance_name
-
# attach splash screen to the main window to help GC
w.__splash_screen = splash
@@ -57,3 +108,7 @@ def show_dialog(app):
if w.is_first_launch():
welcome_widget = w._welcome_msg()
welcome_widget.exec_()
+
+ # Called on all DCCs as a precaution in case other applications are affected.
+ # Safe for unaffected DCCs - the function checks WS_EX_TOPMOST at OS level first.
+ QtCore.QTimer.singleShot(0, lambda: _clear_stay_on_top(w.window()))
diff --git a/python/tk_multi_loader/api/manager.py b/python/tk_multi_loader/api/manager.py
index c95994f..32bf123 100644
--- a/python/tk_multi_loader/api/manager.py
+++ b/python/tk_multi_loader/api/manager.py
@@ -86,7 +86,13 @@ def get_actions_for_publish(self, sg_data, ui_area):
# this publish does not have a type
publish_type = "undefined"
else:
- publish_type = publish_type_dict["name"]
+ # Preference the code field if it exists
+ # but fallback to name for publishes that don't have it.
+ publish_type = (
+ publish_type_dict["code"]
+ if "code" in publish_type_dict
+ else publish_type_dict["name"]
+ )
# check if we have logic configured to handle this publish type.
mappings = self._bundle.get_setting("action_mappings")
@@ -94,8 +100,10 @@ def get_actions_for_publish(self, sg_data, ui_area):
return []
# returns a structure on the form
# { "Maya Scene": ["reference", "import"] }
- actions = mappings.get(publish_type, [])
- actions.extend(mappings.get("All", []))
+ # IMPORTANT: Make a copy to avoid modifying the cached config dict
+ actions = list(mappings.get(publish_type, []))
+ if len(actions) == 0:
+ actions.extend(list(mappings.get("All", [])))
if len(actions) == 0:
return []
@@ -122,6 +130,7 @@ def get_actions_for_publish(self, sg_data, ui_area):
sg_publish_data=sg_data,
actions=actions,
ui_area=ui_area_str,
+ am_base_obj=self.get_am_base_obj(),
)
except Exception:
self._logger.exception("Could not execute generate_actions hook.")
@@ -203,6 +212,22 @@ def get_actions_for_publishes(self, sg_data_list, ui_area):
)
intersection_actions[action_name] = actions_list
+ # Filter out actions not allowed for multi-select.
+ # When multiple publishes are selected, only show actions that are allowed for
+ # multi-select. If any action dict for a given name has 'multi_select' set to False,
+ # that action is excluded from the available actions.
+ if len(sg_data_list) > 1:
+ filtered_actions = {}
+ for action_name, action_list in intersection_actions.items():
+ allow_multiselect = True
+ for action_dict in action_list:
+ if not action_dict["action"].get("multi_select", True):
+ allow_multiselect = False
+ break
+ if allow_multiselect:
+ filtered_actions[action_name] = action_list
+ intersection_actions = filtered_actions
+
return intersection_actions
def execute_action(self, sg_data, action):
@@ -219,6 +244,7 @@ def execute_action(self, sg_data, action):
name=action["name"],
params=action["params"],
sg_publish_data=sg_data,
+ am_base_obj=self.get_am_base_obj(),
)
except Exception as e:
self._logger.exception(
@@ -239,7 +265,10 @@ def execute_multiple_actions(self, actions):
try:
self._bundle.execute_hook_method(
- "actions_hook", "execute_multiple_actions", actions=actions
+ "actions_hook",
+ "execute_multiple_actions",
+ actions=actions,
+ am_base_obj=self.get_am_base_obj(),
)
except Exception as e:
self._logger.exception(
@@ -255,7 +284,7 @@ def get_actions_for_entity(self, sg_data):
:param sg_data: Shotgun data dictionary representing the entity we want to get actions for.
:return: List of dictionaries, each with keys name, params, caption and description
"""
- entity_type = sg_data.get("type", None)
+ entity_type = sg_data.get("type", None) if sg_data else None
# check if we have logic configured to handle this publish type.
mappings = self._bundle.get_setting("entity_mappings")
@@ -264,7 +293,7 @@ def get_actions_for_entity(self, sg_data):
# returns a structure on the form
# { "Shot": ["reference", "import"] }
- actions = mappings.get(entity_type, [])
+ actions = list(mappings.get(entity_type, []))
if len(actions) == 0:
return []
@@ -281,6 +310,7 @@ def get_actions_for_entity(self, sg_data):
sg_publish_data=sg_data,
actions=actions,
ui_area="main",
+ am_base_obj=self.get_am_base_obj(),
) # folder options only found in main ui area
except Exception:
self._logger.exception("Could not execute generate_actions hook.")
@@ -300,8 +330,9 @@ def has_actions(self, publish_type):
# returns a structure on the form
# { "Maya Scene": ["reference", "import"] }
- my_mappings = mappings.get(publish_type, [])
- my_mappings.extend(mappings.get("All", []))
+ # IMPORTANT: Make a copy to avoid modifying the cached config dict
+ my_mappings = list(mappings.get(publish_type, []))
+ my_mappings.extend(list(mappings.get("All", [])))
return len(my_mappings) > 0
@@ -319,3 +350,10 @@ def _fix_timestamp(sg_data):
unix_timestamp, shotgun_api3.sg_timezone.LocalTimezone()
)
sg_data["created_at"] = sg_timestamp
+
+ def get_am_base_obj(self) -> "FlowAMActions | None":
+ """ """
+ if sgtk.platform.current_bundle().get_setting("enable_flowam", False):
+ from ..medm import FlowAMActions
+
+ return FlowAMActions()
diff --git a/python/tk_multi_loader/build_asset_dialog.py b/python/tk_multi_loader/build_asset_dialog.py
new file mode 100644
index 0000000..4628d30
--- /dev/null
+++ b/python/tk_multi_loader/build_asset_dialog.py
@@ -0,0 +1,214 @@
+# Copyright (c) 2026 Shotgun Software Inc.
+#
+# CONFIDENTIAL AND PROPRIETARY
+#
+# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit
+# Source Code License included in this distribution package. See LICENSE.
+# By accessing, using, copying or modifying this work you indicate your
+# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
+# not expressly granted therein are reserved by Shotgun Software Inc.
+
+from __future__ import annotations # needed for Houdini support
+
+import sgtk
+from sgtk.platform.qt import QtGui
+
+from .medm.template_queries import get_template_pipeline_steps, get_templates
+from .ui.build_asset_dialog import Ui_BuildAssetDialog
+
+# Toolkit logger
+logger = sgtk.LogManager.get_logger(__name__)
+
+
+class BuildAssetDialog(QtGui.QDialog):
+ """
+ Custom dialog for building new asset.
+ Presents options for building from new scene, current scene, or template.
+ Dynamically updates available templates based on selected pipeline step.
+ """
+
+ def __init__(
+ self,
+ project_id: str,
+ parent: QtGui.QWidget | None = None,
+ pipeline_step: str | None = None,
+ ) -> None:
+ """
+ Initializes the BuildAssetDialog.
+
+ Args:
+ project_id: Id of AM project to be queried.
+ parent: The parent QWidget for this dialog, default to None.
+ pipeline_step: Preselected pipeline step. If provided, it is stored in
+ self.step and used to configure the pipeline_step_combo_box.
+ When a value is given, the combobox is populated
+ with this single option and then disabled. If None,
+ the combobox is populated with the full list of available
+ pipeline steps and remains enabled.
+
+ Notes
+ -----
+ The presence of pipeline_step determines both the contents
+ and the enabled state of the pipeline_step_combo_box.
+ """
+ super().__init__(parent)
+
+ _flow = sgtk.platform.import_framework("tk-framework-flowam", "flow")
+ _FlowError = _flow.FlowError
+ _Project = _flow.data.Project
+ self._CreateMode = _flow.asset_management.CreateMode
+ self._get_template_source_path = _flow.asset_management.get_template_source_path
+
+ # Query the project entity
+ try:
+ self.project = _Project(project_id)
+ except _FlowError as exc:
+ raise ValueError(f"Project not found: {project_id}") from exc
+
+ self.build = None
+ self.step = pipeline_step
+ self.template = None
+ # Maps of entity names to entity objects
+ self.pipeline_steps = {}
+ self.templates = {}
+ # Template source path based on user's selection
+ self.template_source_path = ""
+
+ self.ui = Ui_BuildAssetDialog()
+ self.ui.setupUi(self)
+
+ ok_button = self.ui.build_button_box.button(
+ QtGui.QDialogButtonBox.StandardButton.Ok
+ )
+ ok_button.setText("Build")
+
+ # Populate combo box from options list
+ self.ui.build_mode_combo_box.addItems(
+ [
+ self._CreateMode.NEW.value,
+ self._CreateMode.CURRENT.value,
+ self._CreateMode.TEMPLATE.value,
+ ]
+ )
+
+ self.ui.build_mode_combo_box.currentTextChanged.connect(
+ self.on_build_option_changed
+ )
+ self.ui.pipeline_step_combo_box.currentTextChanged.connect(
+ self.on_pipeline_step_changed
+ )
+ self.ui.templateWidget.hide()
+ self.setMinimumHeight(0)
+ self.setMinimumWidth(310)
+ self.adjustSize()
+
+ # Stub Utilities
+ def get_pipeline_steps(self) -> list[str]:
+ """
+ Returns a list of pipeline steps provided by the Flow AM framework.
+
+ Returns:
+ list[str]: A list of pipeline step names.
+ """
+ pipeline_steps = get_template_pipeline_steps(self.project)
+ pipeline_step_names = []
+ for pipeline_step in pipeline_steps:
+ self.pipeline_steps[pipeline_step.name] = pipeline_step
+ pipeline_step_names.append(pipeline_step.name)
+ return pipeline_step_names
+
+ def get_pipeline_step_templates(self, step: str) -> list[str]:
+ """
+ Returns a list of templates for a given pipeline step.
+
+ Args:
+ step (str): The name of the pipeline step.
+
+ Returns:
+ list[str]: A list of template names for the specified pipeline step.
+ """
+ pipeline_step = self.pipeline_steps[step]
+ templates = get_templates(pipeline_step)
+ template_names = []
+ for template in templates:
+ self.templates[template.name] = template
+ template_names.append(template.name)
+ return template_names
+
+ # Slots
+ def on_build_option_changed(self, text: str) -> None:
+ """
+ Handles changes to the build option selection.
+
+ Args:
+ text (str): The new build option selected.
+ """
+ is_template_mode = self._CreateMode(text) == self._CreateMode.TEMPLATE
+
+ self.setUpdatesEnabled(False)
+ self.ui.templateWidget.setVisible(is_template_mode)
+ self.ui.pipeline_step_combo_box.clear()
+
+ if is_template_mode and self.step:
+ self.ui.pipeline_step_combo_box.addItems([self.step])
+ self.ui.pipeline_step_combo_box.setCurrentText(self.step)
+
+ elif is_template_mode:
+ self.ui.pipeline_step_combo_box.addItems(self.get_pipeline_steps())
+
+ else:
+ self.ui.templates_combo_box.clear()
+ self.setMinimumSize(0, 0)
+ self.step = None
+ self.template = None
+ self.template_source_path = ""
+ self.templates = {}
+
+ self.layout().activate()
+ self.resize(self.width(), self.sizeHint().height())
+ self.setUpdatesEnabled(True)
+
+ def on_pipeline_step_changed(self, step: str) -> None:
+ """
+ Handles changes to the pipeline step selection.
+
+ Args:
+ step (str): The new pipeline step selected.
+
+ Returns:
+ None.
+ """
+ if not step:
+ return
+
+ self.ui.templates_combo_box.clear()
+ self.ui.templates_combo_box.addItems(self.get_pipeline_step_templates(step))
+
+ def on_build_clicked(self) -> None:
+ """
+ Handles the build button click event.
+
+ Returns:
+ None.
+ """
+ self.build = self._CreateMode(self.ui.build_mode_combo_box.currentText())
+
+ if self.build == self._CreateMode.TEMPLATE:
+ self.step = self.ui.pipeline_step_combo_box.currentText()
+ self.template = self.ui.templates_combo_box.currentText()
+ if self.template and self.template in self.templates:
+ template = self.templates[self.template]
+ self.template_source_path = self._get_template_source_path(template)
+ else:
+ self.step = None
+ self.template = None
+ self.template_source_path = ""
+
+ logger.info(
+ f"Building {self.build} from {self.step} using template {self.template}"
+ )
+
+ def accept(self) -> None:
+ """Override accept to ensure dialog closes properly."""
+ self.on_build_clicked()
+ super().accept()
diff --git a/python/tk_multi_loader/build_template_dialog.py b/python/tk_multi_loader/build_template_dialog.py
new file mode 100644
index 0000000..079e897
--- /dev/null
+++ b/python/tk_multi_loader/build_template_dialog.py
@@ -0,0 +1,137 @@
+# Copyright (c) 2026 Shotgun Software Inc.
+#
+# CONFIDENTIAL AND PROPRIETARY
+#
+# This work is provided "AS IS" and subject to the Shotgun Pipeline Toolkit
+# Source Code License included in this distribution package. See LICENSE.
+# By accessing, using, copying or modifying this work you indicate your
+# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
+# not expressly granted therein are reserved by Shotgun Software Inc.
+
+from __future__ import annotations # needed for Houdini support
+
+import sgtk
+from sgtk.platform.qt import QtGui
+
+from .medm.template_queries import find_template_pipeline_step, get_templates
+from .ui.build_template_dialog import Ui_BuildTemplateDialog
+
+# Toolkit logger
+logger = sgtk.LogManager.get_logger(__name__)
+
+
+class BuildTemplateDialog(QtGui.QDialog):
+ """
+ Custom dialog for selecting a template to build an asset from.
+ """
+
+ def __init__(
+ self,
+ project_id: str,
+ pipeline_steps: list[str] | None = None,
+ parent: QtGui.QWidget | None = None,
+ ) -> None:
+ super().__init__(parent)
+
+ _flow = sgtk.platform.import_framework("tk-framework-flowam", "flow")
+ _FlowError = _flow.FlowError
+ _Project = _flow.data.Project
+ self._CreateMode = _flow.asset_management.CreateMode
+
+ # Query the project entity
+ try:
+ self.project = _Project(project_id)
+ except _FlowError as exc:
+ raise ValueError(f"Project not found: {project_id}") from exc
+
+ if not pipeline_steps:
+ raise ValueError("Pipeline steps must be provided to populate the dialog.")
+
+ self.step = None
+ self.template = None
+ self.description = None
+ self.mode = None
+
+ self.ui = Ui_BuildTemplateDialog()
+ self.ui.setupUi(self)
+
+ self.ui.build_mode_combo_box.addItems(
+ [self._CreateMode.NEW.value, self._CreateMode.CURRENT.value]
+ )
+
+ self.ui.pipeline_step_combo_box.addItems(pipeline_steps)
+
+ # Obtain the button to disconnect the default slot to avoid to close the
+ # dialog if the validation fails
+ self.ok_button = self.ui.build_template_button_box.button(
+ QtGui.QDialogButtonBox.Ok
+ )
+ self.ok_button.clicked.disconnect()
+ self.ok_button.clicked.connect(self.on_build_template_clicked)
+
+ self.ui.template_name_line_edit.textChanged.connect(
+ self._update_ok_button_state
+ )
+ self._update_ok_button_state()
+
+ def _update_ok_button_state(self) -> None:
+ """Enable OK button only when required fields are filled."""
+ has_template = bool(self.ui.template_name_line_edit.text().strip())
+ self.ok_button.setEnabled(has_template)
+
+ def on_build_template_clicked(self) -> None:
+ """
+ Handler for when the build template button is clicked.
+ Gathers input data.
+ """
+ self.mode = self._CreateMode(self.ui.build_mode_combo_box.currentText())
+ self.step = self.ui.pipeline_step_combo_box.currentText()
+ self.template = self.ui.template_name_line_edit.text().strip()
+ self.description = self.ui.description_text_edit.toPlainText()
+
+ template_name_validation_msg = self.__validate_template_name(self.template)
+ if template_name_validation_msg:
+ QtGui.QMessageBox.warning(
+ self,
+ template_name_validation_msg["title"],
+ template_name_validation_msg["message"],
+ )
+ return
+
+ self.accept()
+
+ def __validate_template_name(self, template_name: str) -> dict[str, str] | None:
+ """
+ Validates the template name provided by the user.
+ Ensures the name is not empty and does not already exist for the
+ selected pipeline step.
+
+ Args:
+ template_name (str): The name of the template to validate.
+
+ Returns:
+ dict[str, str] | None: A dictionary with 'title' and 'message'
+ keys if validation fails, otherwise None.
+ """
+ if not template_name:
+ return {
+ "title": "Input Error",
+ "message": "Template name cannot be empty.",
+ }
+
+ pipeline_step = find_template_pipeline_step(self.project, self.step)
+ if not pipeline_step:
+ return None
+
+ available_templates = get_templates(pipeline_step)
+ available_template_names = [template.name for template in available_templates]
+ if template_name in available_template_names:
+ return {
+ "title": "Duplicate Template Name",
+ "message": (
+ f"A template with the name '{template_name}' already exists. "
+ "Please choose a different name."
+ ),
+ }
+
+ return None
diff --git a/python/tk_multi_loader/constants.py b/python/tk_multi_loader/constants.py
index 62fece8..ca94e8e 100644
--- a/python/tk_multi_loader/constants.py
+++ b/python/tk_multi_loader/constants.py
@@ -13,27 +13,93 @@
"""
-# fields to pull down for published files
-PUBLISHED_FILES_FIELDS = [
- "name",
- "version_number",
- "image",
- "entity",
- "path",
- "description",
- "sg_status_list",
- "task",
- "task.Task.sg_status_list",
- "task.Task.due_date",
- "project",
- "task.Task.content",
- "created_by",
- "created_at",
- "version", # note: not supported on TankPublishedFile so always None
- "version.Version.sg_status_list",
- "created_by.HumanUser.image",
-]
+# Fields to query during model initialization for different entity types for detail panel usage
+ENTITY_TYPE_DETAIL_PANEL_FIELDS = {
+ "PublishedFile": [
+ "name",
+ "description",
+ "entity",
+ "project",
+ "version_number",
+ "version",
+ "version.Version.sg_status_list",
+ "sg_status_list",
+ "task",
+ "task.Task.content",
+ "task.Task.sg_status_list",
+ "task.Task.due_date",
+ "path",
+ "created_by",
+ "created_at",
+ "image",
+ "created_by.HumanUser.image",
+ ],
+ "Task": [
+ "content",
+ "sg_status_list",
+ "assigned_to",
+ "due_date",
+ "entity",
+ "project",
+ "step",
+ ],
+ "Asset": [
+ "name",
+ "description",
+ "sg_status_list",
+ "project",
+ "created_by",
+ "shots",
+ ],
+ "Shot": [
+ "name",
+ "description",
+ "sg_status_list",
+ "project",
+ "created_by",
+ "assets",
+ "sg_cut_in",
+ "sg_cut_out",
+ ],
+}
+
+# Fields to query for different entity types to display in the middle panel
+ENTITY_TYPE_MIDDLE_PANEL_FIELDS = {
+ "PublishedFile": [
+ "name",
+ "description",
+ "entity",
+ "project",
+ "version_number",
+ "version",
+ "version.Version.sg_status_list",
+ "sg_status_list",
+ "task",
+ "task.Task.content",
+ "task.Task.sg_status_list",
+ "task.Task.due_date",
+ "path",
+ "created_by",
+ "created_at",
+ "image",
+ "created_by.HumanUser.image",
+ ],
+ "Asset": ["name", "description", "sg_status_list", "created_by"],
+ "Shot": [
+ "name",
+ "description",
+ "sg_status_list",
+ "project",
+ "sg_sequence",
+ "sg_cut_in",
+ "sg_cut_out",
+ ],
+}
# left hand side tree view search only kicks in
# after a certain number have been typed in.
TREE_SEARCH_TRIGGER_LENGTH = 2
+
+# FlowAM versions starts with 0 and FlowPT versions starts with 1.
+# This is used to identify a FlowAM draft version in the UI.
+DRAFT_VERSION_IDENTIFIER = -1
diff --git a/python/tk_multi_loader/delegate_publish_history.py b/python/tk_multi_loader/delegate_publish_history.py
index b393b0d..ee4ba32 100644
--- a/python/tk_multi_loader/delegate_publish_history.py
+++ b/python/tk_multi_loader/delegate_publish_history.py
@@ -124,7 +124,7 @@ def calculate_size():
:returns: Size of the widget
"""
- return QtCore.QSize(200, 90)
+ return QtCore.QSize(200, 50)
class SgPublishHistoryDelegate(shotgun_view.EditSelectedWidgetDelegate):
@@ -217,7 +217,7 @@ def _on_before_paint(self, widget, model_index, style_options):
# v004 (2014-02-21 12:34)
header_str = ""
- header_str += "Version %03d" % (
+ header_str += "Version %03d" % (
sg_item.get("version_number") or 0
)
@@ -226,12 +226,12 @@ def _on_before_paint(self, widget, model_index, style_options):
date_str = datetime.datetime.fromtimestamp(created_unixtime).strftime(
"%Y-%m-%d %H:%M"
)
- header_str += " (%s)" % date_str
+ header_str += " - %s" % date_str
except:
pass
# set the little description bit next to the artist icon
- desc_str = sg_item.get("description") or "No Description Given"
+ desc_str = sg_item.get("description") or "N/A"
# created_by is set to None if the user has been deleted.
if sg_item.get("created_by") and sg_item["created_by"].get("name"):
author_str = sg_item["created_by"].get("name")
diff --git a/python/tk_multi_loader/delegate_publish_list.py b/python/tk_multi_loader/delegate_publish_list.py
index fc9f342..dcae6f6 100644
--- a/python/tk_multi_loader/delegate_publish_list.py
+++ b/python/tk_multi_loader/delegate_publish_list.py
@@ -8,10 +8,18 @@
# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
# not expressly granted therein are reserved by Shotgun Software Inc.
-import sgtk
-from sgtk.platform.qt import QtCore, QtGui
import datetime
+
+import sgtk
+from sgtk.platform.qt import QtCore
+
from .model_latestpublish import SgLatestPublishModel
+from .constants import DRAFT_VERSION_IDENTIFIER
+from .ui.widget_publish_list import Ui_PublishListWidget
+from .delegate_publish import PublishWidget, PublishDelegate
+from .utils import create_fields_display_html
+
+from . import model_item_data
# import the shotgun_model and view modules from the shotgun utils framework
shotgun_model = sgtk.platform.import_framework(
@@ -22,10 +30,6 @@
)
shotgun_view = sgtk.platform.import_framework("tk-framework-qtwidgets", "views")
-from .ui.widget_publish_list import Ui_PublishListWidget
-from .delegate_publish import PublishWidget, PublishDelegate
-from . import model_item_data
-
class PublishListWidget(PublishWidget):
"""
@@ -65,6 +69,17 @@ class SgPublishListDelegate(PublishDelegate):
Delegate which 'glues up' the List widget with a QT View.
"""
+ def __init__(self, *args, **kwargs):
+ """
+ Initialize the delegate and load app settings.
+ """
+ super(SgPublishListDelegate, self).__init__(*args, **kwargs)
+
+ self._app = sgtk.platform.current_bundle()
+ self._list_entity_fields = self._app.get_setting(
+ "entity_fields_middle_panel_list", {}
+ )
+
def _create_widget(self, parent):
"""
Widget factory as required by base class. The base class will call this
@@ -84,6 +99,7 @@ def _format_folder(self, model_index, widget):
# Extract the Shotgun data and field value from the model index.
sg_data, field_value = model_item_data.get_item_data(model_index)
+ entity_type = sg_data.get("type") if sg_data else None
# by default, just display the value
main_text = field_value
@@ -94,7 +110,6 @@ def _format_folder(self, model_index, widget):
and "name" in field_value
and "type" in field_value
):
- # intermediate node with entity link
field_value_type = shotgun_globals.get_type_display_name(
field_value["type"]
)
@@ -104,6 +119,23 @@ def _format_folder(self, model_index, widget):
field_value["name"],
)
+ intermediate_entity_type = field_value.get("type")
+ configured_fields = self._list_entity_fields.get(
+ intermediate_entity_type, []
+ )
+ try:
+ small_text = create_fields_display_html(
+ configured_fields, field_value, max_chars_per_line=60, max_lines=3
+ )
+ except Exception as exc:
+ self._app.logger.warning(
+ "Unable to render configured fields for %s entity in list view. Error: %s",
+ intermediate_entity_type,
+ exc,
+ exc_info=True,
+ )
+ small_text = ""
+
elif isinstance(field_value, list):
# this is a list of some sort. Loop over all elements and extract a comma separated list.
# this can be a multi link field but also a field like a tags field or a non-entity link type field.
@@ -126,13 +158,52 @@ def _format_folder(self, model_index, widget):
main_text = "%s
%s" % (types, names)
elif sg_data:
- # this is a leaf node
- display_name = shotgun_globals.get_type_display_name(sg_data["type"])
+ display_name = shotgun_globals.get_type_display_name(entity_type)
main_text = "%s %s" % (
display_name,
field_value,
)
- small_text = sg_data.get("description") or "No description given."
+
+ html_parts = []
+
+ default_small_text_field = ["description"]
+ try:
+ default_field_html = create_fields_display_html(
+ default_small_text_field,
+ sg_data,
+ max_chars_per_line=60,
+ max_lines=3,
+ )
+ if default_field_html:
+ html_parts.append(default_field_html)
+ except Exception as exc:
+ self._app.logger.warning(
+ "Unable to render default fields for %s entity in list view. Error: %s",
+ entity_type,
+ exc,
+ exc_info=True,
+ )
+
+ configured_fields = self._list_entity_fields.get(entity_type, [])
+ try:
+ additional_fields_html = create_fields_display_html(
+ configured_fields,
+ sg_data,
+ filter_fields=default_small_text_field,
+ max_chars_per_line=60,
+ max_lines=3,
+ )
+ if additional_fields_html:
+ html_parts.append(additional_fields_html)
+ except Exception as exc:
+ self._app.logger.warning(
+ "Unable to render configured fields for %s entity in list view. Error: %s",
+ entity_type,
+ exc,
+ exc_info=True,
+ )
+
+ small_text = "
".join(html_parts)
widget.set_text(main_text, small_text)
@@ -144,62 +215,28 @@ def _format_publish(self, model_index, widget):
:param widget: widget to adjust
"""
- # example data:
-
- # {'code': 'aaa_00010_F004_C003_0228F8_v000.%04d.dpx',
- # 'created_at': 1425378837.0,
- # 'created_by': {'id': 42, 'name': 'Manne Ohrstrom', 'type': 'HumanUser'},
- # 'created_by.HumanUser.image': 'https://...',
- # 'description': 'testing testing, 1,2,3',
- # 'entity': {'id': 1660, 'name': 'aaa_00010', 'type': 'Shot'},
- # 'id': 1340,
- # 'image': 'https:...',
- # 'name': 'aaa_00010, F004_C003_0228F8',
- # 'path': {'content_type': 'image/dpx',
- # 'id': 24116,
- # 'link_type': 'local',
- # 'local_path': '/mnt/projects...',
- # 'local_path_linux': '/mnt/projects...',
- # 'local_path_mac': '/mnt/projects...',
- # 'local_path_windows': 'z:\\mnt\\projects...',
- # 'local_storage': {'id': 4,
- # 'name': 'primary',
- # 'type': 'LocalStorage'},
- # 'name': 'aaa_00010_F004_C003_0228F8_v000.%04d.dpx',
- # 'type': 'Attachment',
- # 'url': 'file:///mnt/projects...'},
- # 'project': {'id': 289, 'name': 'Climp', 'type': 'Project'},
- # 'published_file_type': {'id': 53,
- # 'name': 'Flame Render',
- # 'type': 'PublishedFileType'},
- # 'task': None,
- # 'task.Task.content': None,
- # 'task.Task.due_date': None,
- # 'task.Task.sg_status_list': None,
- # 'task_uniqueness': False,
- # 'type': 'PublishedFile',
- # 'version': {'id': 6697,
- # 'name': 'aaa_00010_F004_C003_0228F8_v000',
- # 'type': 'Version'},
- # 'version.Version.sg_status_list': 'rev',
- # 'version_number': 2}
-
- # Publish Name Version 002
sg_data = shotgun_model.get_sg_data(model_index)
+ entity_type = sg_data.get("type") if sg_data else None
+
+ main_text_fields = ["name", "version_number", "entity", "task"]
+ default_small_text_fields = ["created_by", "created_at"]
+
+ configured_fields = self._list_entity_fields.get(entity_type, [])
+ filter_fields = list(
+ dict.fromkeys(main_text_fields + default_small_text_fields)
+ )
+
main_text = "%s" % (sg_data.get("name") or "Unnamed")
version = sg_data.get("version_number")
- vers_str = "%03d" % version if version is not None else "N/A"
+ if version == DRAFT_VERSION_IDENTIFIER:
+ vers_str = "[DRAFT]"
+ else:
+ vers_str = "%03d" % version if version is not None else "N/A"
main_text += " Version %s" % vers_str
- # If we are in "show subfolders mode, this line will contain
- # the entity information (because we are displaying info from several entities
- # in a single view. If show subfolders mode is off, the latest description is shown.
if self._sub_items_mode:
- # show items in subfolders mode enabled
- # get the name of the associated entity
-
main_text += " ("
entity_link = sg_data.get("entity")
@@ -217,28 +254,58 @@ def _format_publish(self, model_index, widget):
main_text += ")"
elif sg_data.get("task") is not None:
- # When not in subfolders mode always show Task info
- # (similar to the logic in the thumbnail view, but always show)
main_text += " (Task %s)" % sg_data["task"]["name"]
- # Quicktime by John Smith at 2014-02-23 10:34
pub_type_str = shotgun_model.get_sanitized_data(
model_index, SgLatestPublishModel.PUBLISH_TYPE_NAME_ROLE
)
created_unixtime = sg_data.get("created_at") or 0
- date_str = datetime.datetime.fromtimestamp(created_unixtime).strftime(
- "%Y-%m-%d %H:%M"
- )
- # created_by is set to None if the user has been deleted.
+ try:
+ if isinstance(created_unixtime, datetime.datetime):
+ date_str = created_unixtime.strftime("%Y-%m-%d %H:%M")
+ elif isinstance(created_unixtime, (int, float)):
+ date_str = datetime.datetime.fromtimestamp(created_unixtime).strftime(
+ "%Y-%m-%d %H:%M"
+ )
+ else:
+ date_str = "Unknown"
+ except (ValueError, OSError) as exc:
+ self._app.logger.warning(
+ "Unable to convert created_at timestamp for %s publish in list view. Error: %s",
+ entity_type,
+ exc,
+ )
+ date_str = "Unknown"
+
if sg_data.get("created_by") and sg_data["created_by"].get("name"):
author_str = sg_data["created_by"].get("name")
else:
author_str = "Unspecified User"
+
small_text = "%s by %s at %s" % (
pub_type_str,
author_str,
date_str,
)
+
+ try:
+ additional_fields_html = create_fields_display_html(
+ configured_fields,
+ sg_data,
+ filter_fields=filter_fields,
+ max_chars_per_line=60,
+ max_lines=3,
+ )
+ if additional_fields_html:
+ small_text += "
" + additional_fields_html
+ except Exception as exc:
+ self._app.logger.warning(
+ "Unable to render configured fields for %s publish in list view. Error: %s",
+ entity_type,
+ exc,
+ exc_info=True,
+ )
+
widget.set_text(main_text, small_text)
def sizeHint(self, style_options, model_index):
diff --git a/python/tk_multi_loader/delegate_publish_thumb.py b/python/tk_multi_loader/delegate_publish_thumb.py
index 5c6a244..47aa26b 100644
--- a/python/tk_multi_loader/delegate_publish_thumb.py
+++ b/python/tk_multi_loader/delegate_publish_thumb.py
@@ -9,10 +9,15 @@
# not expressly granted therein are reserved by Shotgun Software Inc.
import sgtk
-import datetime
-from sgtk.platform.qt import QtCore, QtGui
+from sgtk.platform.qt import QtCore
+
from .model_latestpublish import SgLatestPublishModel
-from .utils import ResizeEventFilter
+from .constants import DRAFT_VERSION_IDENTIFIER
+from .utils import create_fields_display_html
+from .ui.widget_publish_thumb import Ui_PublishThumbWidget
+from .delegate_publish import PublishWidget, PublishDelegate
+
+from . import model_item_data
# import the shotgun_model and view modules from the shotgun utils framework
shotgun_model = sgtk.platform.import_framework(
@@ -23,10 +28,6 @@
)
shotgun_view = sgtk.platform.import_framework("tk-framework-qtwidgets", "views")
-from .ui.widget_publish_thumb import Ui_PublishThumbWidget
-from .delegate_publish import PublishWidget, PublishDelegate
-from . import model_item_data
-
class PublishThumbWidget(PublishWidget):
"""
@@ -69,6 +70,17 @@ class SgPublishThumbDelegate(PublishDelegate):
Delegate which 'glues up' the Thumb widget with a QT View.
"""
+ def __init__(self, *args, **kwargs):
+ """
+ Initialize the delegate and load app settings.
+ """
+ super(SgPublishThumbDelegate, self).__init__(*args, **kwargs)
+
+ self._app = sgtk.platform.current_bundle()
+ self._thumbnail_entity_fields = self._app.get_setting(
+ "entity_fields_middle_panel_thumbnail", {}
+ )
+
def _create_widget(self, parent):
"""
Widget factory as required by base class. The base class will call this
@@ -86,30 +98,44 @@ def _format_folder(self, model_index, widget):
:param widget: Qt widget created by the delegate for rendering.
"""
- # Extract the Shotgun data and field value from the model index.
sg_data, field_value = model_item_data.get_item_data(model_index)
header_text = ""
details_text = ""
+ entity_type = sg_data.get("type") if sg_data else None
if (
isinstance(field_value, dict)
and "name" in field_value
and "type" in field_value
):
- # intermediate node with entity link
header_text = field_value["name"]
details_text = shotgun_globals.get_type_display_name(field_value["type"])
+ intermediate_entity_type = field_value.get("type")
+ configured_fields = self._thumbnail_entity_fields.get(
+ intermediate_entity_type, []
+ )
+ try:
+ additional_fields_html = create_fields_display_html(
+ configured_fields, field_value, max_chars_per_line=40, max_lines=2
+ )
+ if additional_fields_html:
+ details_text += "
" + additional_fields_html
+ except Exception as exc:
+ self._app.logger.warning(
+ "Unable to render configured fields for %s entity in thumbnail view. Error: %s",
+ intermediate_entity_type,
+ exc,
+ exc_info=True,
+ )
+
elif isinstance(field_value, list):
- # this is a list of some sort. Loop over all elements and extract a comma separated list.
formatted_values = []
if len(field_value) == 0:
- # no items in list
formatted_values.append("No Value")
for v in field_value:
if isinstance(v, dict) and "name" in v and "type" in v:
- # This is a link field
if v.get("name"):
formatted_values.append(v.get("name"))
else:
@@ -118,12 +144,25 @@ def _format_folder(self, model_index, widget):
header_text = ", ".join(formatted_values)
elif sg_data:
- # this is a leaf node
header_text = field_value
- details_text = shotgun_globals.get_type_display_name(sg_data["type"])
+ details_text = shotgun_globals.get_type_display_name(entity_type)
+
+ configured_fields = self._thumbnail_entity_fields.get(entity_type, [])
+ try:
+ additional_fields_html = create_fields_display_html(
+ configured_fields, sg_data, max_chars_per_line=40, max_lines=2
+ )
+ if additional_fields_html:
+ details_text += "
" + additional_fields_html
+ except Exception as exc:
+ self._app.logger.warning(
+ "Unable to render configured fields for %s entity in thumbnail view. Error: %s",
+ entity_type,
+ exc,
+ exc_info=True,
+ )
else:
- # other value (e.g. intermediary non-entity link node like sg_asset_type)
header_text = field_value
widget.set_text(header_text, details_text)
@@ -136,90 +175,31 @@ def _format_publish(self, model_index, widget):
:param widget: Qt widget created by the delegate for rendering.
"""
- # this is a publish!
sg_data = shotgun_model.get_sg_data(model_index)
+ entity_type = sg_data.get("type") if sg_data else None
+
+ header_text_fields = ["name", "version_number", "task"]
+ configured_fields = self._thumbnail_entity_fields.get(entity_type, [])
header_text = ""
details_text = ""
- # example data:
-
- # {'code': 'aaa_00010_F004_C003_0228F8_v000.%04d.dpx',
- # 'created_at': 1425378837.0,
- # 'created_by': {'id': 42, 'name': 'Manne Ohrstrom', 'type': 'HumanUser'},
- # 'created_by.HumanUser.image': 'https://...',
- # 'description': 'testing testing, 1,2,3',
- # 'entity': {'id': 1660, 'name': 'aaa_00010', 'type': 'Shot'},
- # 'id': 1340,
- # 'image': 'https:...',
- # 'name': 'aaa_00010, F004_C003_0228F8',
- # 'path': {'content_type': 'image/dpx',
- # 'id': 24116,
- # 'link_type': 'local',
- # 'local_path': '/mnt/projects...',
- # 'local_path_linux': '/mnt/projects...',
- # 'local_path_mac': '/mnt/projects...',
- # 'local_path_windows': 'z:\\mnt\\projects...',
- # 'local_storage': {'id': 4,
- # 'name': 'primary',
- # 'type': 'LocalStorage'},
- # 'name': 'aaa_00010_F004_C003_0228F8_v000.%04d.dpx',
- # 'type': 'Attachment',
- # 'url': 'file:///mnt/projects...'},
- # 'project': {'id': 289, 'name': 'Climp', 'type': 'Project'},
- # 'published_file_type': {'id': 53,
- # 'name': 'Flame Render',
- # 'type': 'PublishedFileType'},
- # 'task': None,
- # 'task.Task.content': None,
- # 'task.Task.due_date': None,
- # 'task.Task.sg_status_list': None,
- # 'task_uniqueness': False,
- # 'type': 'PublishedFile',
- # 'version': {'id': 6697,
- # 'name': 'aaa_00010_F004_C003_0228F8_v000',
- # 'type': 'Version'},
- # 'version.Version.sg_status_list': 'rev',
- # 'version_number': 2}
-
- # get the name (lighting v3)
name_str = "Unnamed"
if sg_data.get("name"):
name_str = sg_data.get("name")
- if sg_data.get("version_number"):
- name_str += " v%s" % sg_data.get("version_number")
-
- # now we are tracking whether this item has a unique task/name/type combo
- # or not via the specially injected task_uniqueness boolean.
- # If this is true, that means that this is the only item in the listing
- # with this name/type combo, and we can render its display name on two
- # lines, name first and then type, e.g.:
- # MyScene, v3
- # Maya Render
- #
- # However, there can be multiple *different* tasks which have the same
- # name/type combo - in this case, we want to display the task name too
- # since this is what differentiates the data. In that case we display it:
- # MyScene, v3 (Layout)
- # Maya Render
- #
+ version_number = sg_data.get("version_number")
+ if version_number == DRAFT_VERSION_IDENTIFIER:
+ name_str += " [DRAFT]"
+ elif version_number:
+ name_str += " v%s" % version_number
+
if sg_data.get("task_uniqueness") == False and sg_data.get("task") is not None:
name_str += " (%s)" % sg_data["task"]["name"]
- # make this the title of the card
header_text = name_str
- # check if we are in "deep mode". In that case, display the entity link info
- # on the thumb card. Otherwise, display the type.
if self._sub_items_mode:
-
- # display this publish in sub items node
- # in this case we want to display the following two lines
- # main_body v3
- # Shot AAA001
-
- # get the name of the associated entity
entity_link = sg_data.get("entity")
if entity_link is None:
details_text = "Unlinked"
@@ -230,12 +210,28 @@ def _format_publish(self, model_index, widget):
details_text = "%s %s" % (entity_link_type, entity_link["name"])
else:
- # std publish - render with a name and a publish type
- # main_body v3
- # Render
- details_text = shotgun_model.get_sanitized_data(
+ base_type = shotgun_model.get_sanitized_data(
model_index, SgLatestPublishModel.PUBLISH_TYPE_NAME_ROLE
)
+ details_text = base_type
+
+ try:
+ additional_fields_html = create_fields_display_html(
+ configured_fields,
+ sg_data,
+ filter_fields=header_text_fields,
+ max_chars_per_line=40,
+ max_lines=2,
+ )
+ if additional_fields_html:
+ details_text += "
" + additional_fields_html
+ except Exception as exc:
+ self._app.logger.warning(
+ "Unable to render configured fields for %s publish in thumbnail view. Error: %s",
+ entity_type,
+ exc,
+ exc_info=True,
+ )
widget.set_text(header_text, details_text)
@@ -246,6 +242,5 @@ def sizeHint(self, style_options, model_index):
:param style_options: QT style options
:param model_index: Model item to operate on
"""
- # base the size of each element off the icon size property of the view
scale_factor = self._view.iconSize().width()
return PublishThumbWidget.calculate_size(scale_factor)
diff --git a/python/tk_multi_loader/dialog.py b/python/tk_multi_loader/dialog.py
index 18abc2c..1a43db7 100644
--- a/python/tk_multi_loader/dialog.py
+++ b/python/tk_multi_loader/dialog.py
@@ -9,31 +9,41 @@
# not expressly granted therein are reserved by Shotgun Software Inc.
+from typing import Any, Optional
+
+import os
+from functools import partial
+from typing import Any
+
import sgtk
from sgtk import TankError
from sgtk.platform.qt import QtCore, QtGui
-from .model_hierarchy import SgHierarchyModel
+from . import constants, model_item_data
+from .banner import Banner
+from .delegate_publish_history import SgPublishHistoryDelegate
+from .delegate_publish_list import SgPublishListDelegate
+from .delegate_publish_thumb import SgPublishThumbDelegate
+from .framework_qtwidgets import ShotgunFilterMenu
+from .loader_action_manager import LoaderActionManager
+from .medm import (
+ MedmEntityModel,
+ MedmLatestPublishModel,
+ MedmPublishHistoryModel,
+ MedmSharedCache,
+ MedmThumbnailService,
+)
from .model_entity import SgEntityModel
+from .model_hierarchy import SgHierarchyModel
from .model_latestpublish import SgLatestPublishModel
+from .model_publishhistory import SgPublishHistoryModel
from .model_publishtype import SgPublishTypeModel
from .model_status import SgStatusModel
-from .proxymodel_latestpublish import SgLatestPublishProxyModel
from .proxymodel_entity import SgEntityProxyModel
-from .delegate_publish_thumb import SgPublishThumbDelegate
-from .delegate_publish_list import SgPublishListDelegate
-from .model_publishhistory import SgPublishHistoryModel
-from .delegate_publish_history import SgPublishHistoryDelegate
+from .proxymodel_latestpublish import SgLatestPublishProxyModel
from .search_widget import SearchWidget
-from .banner import Banner
-from .loader_action_manager import LoaderActionManager
-from .utils import resolve_filters
-from .framework_qtwidgets import ShotgunFilterMenu
-
-from . import constants
-from . import model_item_data
-
from .ui.dialog import Ui_Dialog
+from .utils import get_field_display_name, get_human_readable_value, resolve_filters
# import frameworks
shotgun_model = sgtk.platform.import_framework(
@@ -84,6 +94,12 @@ def __init__(self, action_manager, parent=None):
QtGui.QWidget.__init__(self, parent)
self._action_manager = action_manager
+ # Hold a reference to the current animation to prevent GC mid-run
+ self._current_animation = None
+
+ # FlowAM tree view - only created when enable_flowam is enabled
+ self._medm_tree_view = None
+
# The loader app can be invoked from other applications with a custom
# action manager as a File Open-like dialog. For these managers, we won't
# be using the banner system.
@@ -114,6 +130,12 @@ def __init__(self, action_manager, parent=None):
# Do not allow items to be dragged and moved around.
self.ui.publish_view.setMovement(QtGui.QListView.Static)
+ # Set initial splitter proportions: left panel, middle publish area, right details
+ self.ui.splitter.setStretchFactor(0, 3)
+ self.ui.splitter.setStretchFactor(1, 7)
+ self.ui.splitter.setStretchFactor(2, 3)
+ self.ui.splitter.setSizes([360, 840, 380])
+
#################################################
# maintain a list where we keep a reference to
# all the dynamic UI we create. This is to make
@@ -144,6 +166,22 @@ def __init__(self, action_manager, parent=None):
self._publish_history_model = SgPublishHistoryModel(self, self._task_manager)
+ # FlowAM objects are only instantiated when enable_flowam is enabled.
+ # tk-framework-flowam is required by these classes but is not available
+ # in all environments (e.g. CI). Keeping these as None when FlowAM is
+ # disabled prevents a hard startup failure in those environments.
+ self._medm_cache = None
+ self._medm_thumbnail_service = None
+ self._medm_history_model = None
+ if sgtk.platform.current_bundle().get_setting("enable_flowam", False):
+ self._medm_cache = MedmSharedCache()
+ self._medm_thumbnail_service = MedmThumbnailService(self._medm_cache, self)
+
+ # FlowAM history model for FlowAM publish items
+ self._medm_history_model = MedmPublishHistoryModel(
+ self, self._task_manager, self._medm_cache, self._medm_thumbnail_service
+ )
+
self._publish_history_model_overlay = ShotgunModelOverlayWidget(
self._publish_history_model, self.ui.history_view
)
@@ -183,13 +221,12 @@ def __init__(self, action_manager, parent=None):
self._no_selection_pixmap = QtGui.QPixmap(":/res/no_item_selected_512x400.png")
self._no_pubs_found_icon = QtGui.QPixmap(":/res/no_publishes_found.png")
- self.ui.detail_playback_btn.clicked.connect(self._on_detail_version_playback)
self._current_version_detail_playback_url = None
# set up right click menu for the main publish view
self._refresh_history_action = QtGui.QAction("Refresh", self.ui.history_view)
self._refresh_history_action.triggered.connect(
- self._publish_history_model.async_refresh
+ self._refresh_current_history_model
)
self.ui.history_view.addAction(self._refresh_history_action)
self.ui.history_view.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
@@ -197,6 +234,11 @@ def __init__(self, action_manager, parent=None):
# if an item in the list is double clicked the default action is run
self.ui.history_view.doubleClicked.connect(self._on_history_double_clicked)
+ # Make the versions list shrink to fit its content instead of
+ # claiming a large fixed area regardless of how many versions exist.
+ self._history_view_max_height = 350
+ self._patch_history_view_sizing()
+
#################################################
# load and initialize cached publish type model
# this model is now only used to get the published file type filters from the config
@@ -299,6 +341,7 @@ def __init__(self, action_manager, parent=None):
self.ui.show_sub_items.toggled.connect(self._on_show_subitems_toggled)
self.ui.check_all.clicked.connect(self._publish_type_model.select_all)
self.ui.check_none.clicked.connect(self._publish_type_model.select_none)
+ self.ui.details_button.toggled.connect(self._on_details_button_toggled)
#################################################
# thumb scaling
@@ -334,12 +377,17 @@ def __init__(self, action_manager, parent=None):
# Set up filtering
app = sgtk.platform.current_bundle()
+ enable_flowam = app.get_setting("enable_flowam", False)
if app.get_setting("use_legacy_published_file_type_filter", False):
# Hide the Filter menu button.
# The legacy filter functionality is always set up, since the filter menu still
# requires some of that functionality.
self._filter_menu = None
self.ui.filter_menu_btn.hide()
+ elif enable_flowam:
+ # Disable filter menu for Flow Asset Management mode - it expects ShotgunModel data
+ self._filter_menu = None
+ self.ui.filter_menu_btn.hide()
else:
# Hide the legacy filter widgets
self.ui.publish_type_list.hide()
@@ -381,6 +429,10 @@ def __init__(self, action_manager, parent=None):
self._load_entity_presets()
+ # Set up the FlowAM tree panel when Flow Asset Management is enabled
+ if enable_flowam:
+ self._setup_medm_tree_panel()
+
#################################################
# restore user app ui settings
self.restore_state()
@@ -533,6 +585,10 @@ def closeEvent(self, event):
shotgun_globals.unregister_bg_task_manager(self._task_manager)
self._task_manager.shut_down()
+ # Shut down the FlowAM thumbnail service if it is running
+ if self._medm_thumbnail_service is not None:
+ self._medm_thumbnail_service.destroy()
+
except:
app = sgtk.platform.current_bundle()
app.log_exception("Error running Loader App closeEvent()")
@@ -597,9 +653,78 @@ def restore_state(self):
########################################################################################
# info bar related
+ def _patch_history_view_sizing(self) -> None:
+ """
+ Override the history QListView's sizeHint so the layout allocates only
+ enough vertical space for the actual version rows (up to a maximum).
+
+ The default QListView.sizeHint() returns a large constant regardless of
+ content, which leaves a big empty gap when there are few versions.
+ """
+ view = self.ui.history_view
+ max_h = self._history_view_max_height
+ original_width = view.sizeHint().width()
+
+ def _content_size_hint():
+ model = view.model()
+ if model and model.rowCount() > 0:
+ row_h = view.sizeHintForRow(0)
+ content_h = row_h * model.rowCount() + 4
+ return QtCore.QSize(original_width, min(content_h, max_h))
+ return QtCore.QSize(original_width, 0)
+
+ view.sizeHint = _content_size_hint
+
+ # Re-evaluate height whenever the model's row count changes
+ if view.model():
+ view.model().rowsInserted.connect(self._update_history_view_height)
+ view.model().rowsRemoved.connect(self._update_history_view_height)
+ view.model().modelReset.connect(self._update_history_view_height)
+
+ def _update_history_view_height(self) -> None:
+ """Resize history_view to exactly fit its content (capped at max)."""
+ view = self.ui.history_view
+ model = view.model()
+ if model and model.rowCount() > 0:
+ row_h = view.sizeHintForRow(0)
+ content_h = row_h * model.rowCount() + 4
+ view.setMaximumHeight(min(content_h, self._history_view_max_height))
+ else:
+ view.setMaximumHeight(0)
+ view.updateGeometry()
+
+ def _on_details_button_toggled(self, checked: bool) -> None:
+ """
+ Triggers a show/hide of the details header with an animation.
+ """
+ if (
+ self._current_animation
+ and self._current_animation.state() == QtCore.QAbstractAnimation.Running
+ ):
+ self._current_animation.stop()
+
+ animation = QtCore.QPropertyAnimation(self.ui.details_header, b"maximumHeight")
+ animation.setDuration(200)
+ animation.setEasingCurve(QtCore.QEasingCurve.InOutQuad)
+
+ if checked:
+ # Release the maximumHeight constraint so the label sizes itself
+ # to its content via the Preferred size policy.
+ animation.setStartValue(0)
+ animation.setEndValue(16777215)
+ else:
+ # Collapse from the actual rendered height, not a stale sizeHint.
+ animation.setStartValue(self.ui.details_header.height())
+ animation.setEndValue(0)
+
+ animation.finished.connect(lambda: setattr(self, "_current_animation", None))
+ self._current_animation = animation
+ animation.start(QtCore.QAbstractAnimation.DeleteWhenStopped)
+
def _on_history_selection(self, selected, deselected):
"""
- Called when the selection changes in the history view in the details panel
+ Called when the selection changes in the history view in the details panel.
+ Updates the main thumbnail in the dialog.
:param selected: Items that have been selected
:param deselected: Items that have been deselected
@@ -607,6 +732,70 @@ def _on_history_selection(self, selected, deselected):
# emit the selection_changed signal
self.selection_changed.emit()
+ # Clear image if no selection
+ indexes = selected.indexes()
+ if not indexes:
+ self.ui.details_image.setScaledContents(True)
+ self.ui.details_image.clear()
+ return
+
+ # Get the selected item from the model
+ proxy_index = indexes[0]
+ proxy_model = proxy_index.model()
+ if not proxy_model:
+ self.ui.details_image.clear()
+ return
+
+ source_index = proxy_model.mapToSource(proxy_index)
+ if not source_index.isValid():
+ self.ui.details_image.clear()
+ return
+
+ source_model = proxy_model.sourceModel()
+ item = source_model.itemFromIndex(source_index)
+ if not item:
+ self.ui.details_image.clear()
+ return
+
+ # Prefer the full downloaded image path stored by the model
+ full_image_path = item.data(SgPublishHistoryModel.FULL_IMAGE_PATH_ROLE)
+ pixmap = None
+
+ if full_image_path and os.path.exists(full_image_path):
+ pixmap = QtGui.QPixmap(full_image_path)
+ if pixmap.isNull():
+ pixmap = None
+
+ # For FlowAM data, fall back to the publish thumbnail role
+ if not pixmap:
+ publish_thumb = item.data(SgPublishHistoryModel.PUBLISH_THUMB_ROLE)
+ if (
+ publish_thumb
+ and isinstance(publish_thumb, QtGui.QPixmap)
+ and not publish_thumb.isNull()
+ ):
+ pixmap = publish_thumb
+
+ # Last resort: item icon
+ if not pixmap:
+ icon = item.icon()
+ if not icon.isNull():
+ pixmap = icon.pixmap(256, 256)
+
+ if not pixmap or pixmap.isNull():
+ self.ui.details_image.clear()
+ return
+
+ # Scale to fit the image label while preserving aspect ratio
+ target_size = self.ui.details_image.size()
+ scaled_pixmap = pixmap.scaled(
+ target_size,
+ QtCore.Qt.KeepAspectRatio,
+ QtCore.Qt.SmoothTransformation,
+ )
+ self.ui.details_image.setPixmap(scaled_pixmap)
+ self.ui.details_image.setScaledContents(False)
+
def _on_history_double_clicked(self, model_index):
"""
When someone double clicks on a publish in the history view, run the
@@ -724,13 +913,13 @@ def _set_details_pane_visiblity(self, visible):
# hide details pane
self._details_pane_visible = False
self.ui.details.setVisible(False)
- self.ui.info.setText("Show Details")
+ self.ui.info.setIcon(QtGui.QIcon(":/res/icon_plus.png"))
else:
# show details pane
self._details_pane_visible = True
self.ui.details.setVisible(True)
- self.ui.info.setText("Hide Details")
+ self.ui.info.setIcon(QtGui.QIcon(":/res/icon_minus.png"))
# if there is something selected, make sure the detail
# section is focused on this
@@ -738,39 +927,128 @@ def _set_details_pane_visiblity(self, visible):
self._setup_details_panel(selection_model.selectedIndexes())
+ def _format_folder_field_value(
+ self,
+ field_name: str,
+ field_value: Any,
+ sg_data: dict,
+ entity_type: str,
+ ) -> str:
+ """Formats field values for Shotgun entity folder items in the details panel.
+
+ :param field_name: Shotgun field name (e.g., 'sg_status_list', 'description')
+ :param field_value: Raw field value from Shotgun
+ :param sg_data: Complete Shotgun entity data dictionary
+ :param entity_type: Shotgun entity type
+ :returns: HTML-formatted string for display in details panel
+ """
+ if field_name == "sg_status_list":
+ if field_value is None:
+ status_name = "No Status"
+ else:
+ status_name = self._status_model.get_long_name(field_value)
+
+ status_color = self._status_model.get_color_str(field_value)
+ if status_color:
+ status_name = "%s █" % (
+ status_name,
+ status_color,
+ )
+ return status_name
+
+ elif field_name == "description":
+ return field_value or "No description entered."
+
+ elif field_name == "code":
+ display_name = shotgun_globals.get_type_display_name(sg_data["type"])
+ return "%s %s" % (display_name, field_value)
+
+ else:
+ return get_human_readable_value(field_value, field_name, entity_type)
+
+ def _format_published_file_field_value(
+ self,
+ field_name: str,
+ field_value: Any,
+ sg_item: dict,
+ entity_type: str,
+ ) -> Optional[str]:
+ """Formats field values for published file items in the details panel.
+
+ :param field_name: Shotgun field name (e.g., 'name', 'version_number', 'entity')
+ :param field_value: Raw field value from Shotgun
+ :param sg_item: Complete published file data dictionary
+ :param entity_type: Shotgun entity type
+ :returns: Formatted string for display in details panel (may contain HTML)
+ """
+ if field_name == "name":
+ return field_value or "No Name"
+
+ elif field_name == "type":
+ return field_value
+
+ elif field_name == "version_number":
+ if field_value == constants.DRAFT_VERSION_IDENTIFIER:
+ return "DRAFT"
+ return "%03d" % field_value if field_value is not None else "N/A"
+
+ elif field_name == "entity":
+ if field_value:
+ display_name = shotgun_globals.get_type_display_name(
+ field_value.get("type")
+ )
+ entity_name = field_value.get("name")
+ return "%s %s" % (display_name, entity_name)
+
+ elif field_name == "task":
+ if field_value:
+ task_name = sg_item.get("task.Task.content", "Unnamed")
+ task_status_code = sg_item.get("task.Task.sg_status_list")
+ if task_status_code:
+ task_status_str = self._status_model.get_long_name(task_status_code)
+ else:
+ task_status_str = "No Status"
+ return "%s (%s)" % (task_name, task_status_str)
+ else:
+ return "No Task"
+
+ elif field_name == "version.Version.sg_status_list":
+ if field_value:
+ return self._status_model.get_long_name(field_value)
+ else:
+ return "No Status"
+
+ else:
+ return get_human_readable_value(field_value, field_name, entity_type)
+
def _setup_details_panel(self, items):
"""
Sets up the details panel with info for a given item.
"""
- def __make_table_row(left, right):
- """
- Helper method to make a detail table row
- """
+ def __make_table_row(left, right, max_chars=80):
+ from .utils import smart_truncate
+
+ if isinstance(right, str) and len(right) > max_chars:
+ right = smart_truncate(right, max_chars)
+ if isinstance(left, str):
+ left = left.replace(" ", " ")
return (
- "
\xb2\xd5\x82[\x8c(\x05\x8cE\x96f\
-\x86\xaa\x14\x1e\xe8\xf7|\xf0\x1d\x02/\xda\xb1/l]\
-\xd3\x03\xcb\x09\xd2c\xa7\x88i\x97r\xda\x0b\xbb\xeb\x9c\
-C/\xcaE\xbfgN\x9c\xc0\x02\xf32[\x1cI\x08\
-cC\xde\xff\xec\xb8\xd3M\xb5\xd2r\xa9\x1c\x0c\xa7\x14\
-\xb6\xc7\xc6\xe8T\x00Xw\x16\x02\xeb\x96\x05\xf0\x91\xb5\
-\x0c@>d\xe9\xac`\xae|\xe5\xf3j\x05\x99q\xde\
-\xc2v\xc2\x82Z'\x88\xc7t\xc1\x8f\x8c\xc1\xd4\xfa\xf9\
-\xcc\x06a\x81\xd9\xc9p\xfc\x9c\xc5\x00p\x1e\xa8\x09x\
-\xec\x19\xdf\xbc\xcc\xb2\xf65D\xa7\xee\xdd\x1axp\xf5\
-\xb0n\x15\x9f\xae\x0e\xd3\xe4\xb0\xef|\xeec\x08\xcc\xbd\
-\xa8\x85)z\xfe\xa9\x91\xb0\x8ej7c\xb8\xb2\xeb\xbd\
-\xe2\xf4\xcd{\x83\xba\xf2\xf3\x0d\xc1\xe0\xed~\x00\x97I\
-\x9fk@\x11\x87\xe4}\xdd\x14\x0fMA\xe1\xc7\x9a)\
-\xeas\x0e\x1f\xeb\x81i\xf2X<\x13\xf6B\xb0\xf8\xee\
-u\xc2\xc7VqQ\x10Ot\xb4\xbd\xad\xa9\xe2e\x09\
-gb_\x11\x15\xd2\x99gx\x913?`6\x04\x8b\
-\x8fG\xc2<\x05b\xbc\xad\x87u\x8c\xf9\xf5\x9e\x05\xb7\
-1\xb4\xe8:\xc7@\x99\x0e~?/\xd2\xb9\xd4F*\
-\x9ds\x0e\xfbQ\x957 ]\x84\xa5 \xd5\x07\x87\xa4\
-\x98\xed`\x1d\xff|X\xe5Np:d-\xd3\x14S\
-\xd59S\x09S\xeb\x95\xab\xa7Z9b\xd7=\xcc\xa9\
-\xae#\xdd\xb3\xb7q\xf9:\x5c':\x92\xbcc\xfc4\
-\x04\x0a+\xe5\x99\x90\x1a\xac\xc1\xe4\x1c\xf6Z\xd1@\x92\
-d\xacl\x5c\xde\xee\x07\x9d+\x9e,\x92\x94\x81\xe8\x9f\
-\xf6\xd1\xeb<\xb1\x99\xa9\xe4~l\x87\xc1\xdbJ\xd7\xc4\
-<\x05\x16\xc0\xd6\x0a\x96\xe6\xcf\xf3\xf3\x17\xdf?\xf0O\
-\xfe\xdf\xff\x1c\xbd\x1b\xf8`\xf1\xc7?\xfa\x84\xff\xca\xdf\
-\xf9\x96\xe7C\x03Z7\xb8\x5c\x22\x11\xd8\xa5#Cg\
-\xaa\x1d\x99\x13\x14\x13\xe7\xca)xi,\x08>]\xa2\
-4hZ]t\x8a\xb8\xc7*\xed\xb1\xe7S\xf0YP\
-\xb1\xa7\x8ee\xb6\xd8\x8e\xa2\x90\x1f\xea\x1d&\xc7I\xe7\
-c\xcfx\xbd\x12\x8d\x8d\xc6\x95\x9d\x93v\xc1Y\x87T\
-2\xb6\xd4\xf0]\xdc\x7fo\x01\xf0{'\x00\xc7\xb1\xbe\
-S \x03\xd4NPB\xa9\xdc\xf5\xd1\xeag\xe1\x0d\xce\
-\xaa+\x9cV8\xcb\x15@k\xbad\x80^\xc6\xa1\xcb\
-Q\xe3\x9e\xb3\x04v\xe2r;\x03o,\xd7\x0a\x02\xe2\
-DK2S0V\xff\x1d\xf7$M\xb4\xa6\xcb\x125\
-\xe6\x84\xa8m\xe6\xdc\x11uPO0`?\x9c\x12p\
-\x84\x0c\xf0\xe2\xd6\x16\x10\x00w6G\xa5\xc0&F\x87\
-]\x1d\x89\x0f\x06_\xef\x073\x09\x04\xc0\xd9S\xc5\x96\
-\x08\xf91\xe0x\xfc2\xd1s\xfbH\x99k\x06K\x10\
-\x08\x03*\x1a\xf5\x03\x9d\xe2Cg%\xfa\xf8\xc1\x84\x03\
-\xa6\x9f\x91\xbd\x06|1\xc7\xd8gO\x19I\xd8\xd6 \
-\xcdB)\x84\xe6\x10V\xc1\xce\xa6u\xb2\xe4\xbd\xe3\x03\
-\xb4\xa5\xcc\xf1\x94X\xfc\x97\x99AH\xf7#\xe1(\x99\
-\x07\xb6a\x940\xbb\xb3|\xee\xe8\xf7\xdcN\x98\x8f\x03\
-w\xf3\xad\x01\x1f[QZ\x1c\xa71\xc3.\xb7\xa6\x82\
-\xd6\xc8\x0f\x18b\xb7u\x1fx\x5c\xad\x0f\xaa&8\xea\
-\xc0G5\xfe8\xb8\xd21\x86v\xb2`\xdd\xd9\xa9\xee\
-\x89<\xfc#Q\xe4b`\xd1\x0aAJ\x06\xec\xa0\xf9\
-\x0c\x90\xe0\xa6\xf3\x9e\xcc\xfaVO>\xc2\x00\xef\x0c\x9f\
-\xfd\xd0ZdMS\xe6\xd9\xb2\x18\x02\xa9k0@o\
-\xf6$W\x8eQ\xdc\xcb<\xb1\x10%\x10Q@\xa0&\
-\xe45\x0f\xf0\xf3\xcf\xd4\xe7{\x89N\xb4LZa\xa3\
-\xf3X\xa2\x93\xf0\x89\x80 o\xfd\xf94N\x81D\xbd\
-\xe0\xa8+y\xe8r\xee\xbd\xe3v\xf5\xb8.\xc4\x946\
-\x052\xd56\x86\xfa\xd4K@{\xc7\xe0\x9c\x84D\x14\
-A-\xd3\xe0\xdc\x87\xb3\x0bk\x9dB\xaa\xd6;bt\
-\x02}\xf9\xd3\xc2\xdb\x9b\xfeow\xe7^\xd4\x19\x8b\xc9\
-q\x17\xba+^\x17\x9d\x16\xc5\xb1\xebN\xc2\xff\x9a>\
-\xc4\x84,\x10\x86\xea\x9b\xbcz~\xef\xa5p\xefj-\
-3' \x00\xd2\xb7\xaf3n\x97\x88\xeb\xe4\x15\x13\x5c\
-\x04\x0f\xa3\x83\x02\x10KD\xf08\xee\xa4\xd9\x80\xe4\xdc\
-\x84\x06v\xe7\xaew\x9e,a1\x82\xca\x8f\x00\x16\xee\
-l;f\x1f\xe0\x83\xde\x9d#K4\xe6\xe1\x03't\
-\x83\xee8\x07\x7f\x06V\xdd\xe6\x80^9\x1d\xf0\xce\xc9\
-\xda\xc7\xeer\x15\xa9\xcf9\x83e\xb6\xc4\xc3\x0a\x80\xd5\
-zG\xab\x9c\xd0\xad\xa9\xe1\xb6\x84\x13\x9f>,\xbf\xc6\
-\x00\xb7K\x1c`<\x5c/\x0es\x1c\x84O\xfe\xdc\x87\
-\xa8\x9et\x19P\xdd>,g\xf7\x9d\x9f\xe5\xebu\xc2\
-\x14\x1c\xd7\xb8\x03,\x14\x8c\xa6r\x06\xb5P\x82v\x9d\
-\xed\x99\xa6h\xc0i\xa9\xb1#\x0b\xc1\x0b\xa8\xd6\x10\x04\
-s\xcb\x89g\x1b#s\xed\xb9V\x18Ock\xec\xa4\
-\xf9\xfeq\xa5I}\x13\xb3\x12r\xadj\x80\xac\xf0\xe0\
-,z\xf6\xc2\x94\xc99Js\xe6x\xf9\x1f)\xe3\xd3\
--\x9c\xcfe\xab\x0d/\x17\xc7\xb8ipbP\x1b'\
-C\xc1\x8d\x9d9W\xcaA\xd6\xcb-5\xe9U:r\
--Xw\xae\x92\xbe\xbco\xb8?\x0e\x18t|\xfdr\
-\xc7\xf7ow,K83Z\xc6\x94g\x14\xee\x97)\
-\x9cy5\x16\x5cE\xe4\xc4\xb5\xdc\x1c=>]&\x5c\
-\xa6\xc0\xc2~\xcb\xd8\x8e\x84\xdb\xe2\xa5S\xa3\xd6\x22z\
-\x83I\x89~\xbd\x11@u\x9di\x07^\x0ff\xf0\xf0\
-\x1ff\x8bx?\xc2\xf7\xa6\x93\xc5\x11\x83\xc5e\xf6'\
-_\xc3\x1a\x10^\xd4\xcb\xdb_\xbb\x00\x98\x8c\xf9u\xad\
-\x14%\xb4\xd6\xf1r\x99\xd4iP1\xcf\x8b\x8a\x97T\
-\xf0\xd0\x98\xf9\xf9\xdf\x07\xcf\x0e\xe7\xe3\xc8\xe7\xe8\xb7\xb7\
-\x8e\xaa\x91ni\x0d\xad\x16\xc1r\xac,%\x8c\xb7\x1d\
-p\x96)8XO1\xa1w\x06\xbd\xd2Z\xb2&~\
-y\xb55\x85\xfd>-bD\x00\xb7\x13,\x925\x1e\
-\xce\xad2[\xbc\x1b\x94B\xd5\xeb\x98\x10x\xd7\x81j\
-\x90\x1b\xd5\xcb\x03\xf6S*\x1f\xf0A7\xe3\x0b\xe8\xb4\
-\xebl'V7\x08\xab\xeb\x00\xd9\x09\xb9Kv\x86q\
-\xc4\xd6Z\xa5\xc5\xb1\x0b\x1d\xe3\xdc\xe1%o\xa2x\xac\
-{>C\x82\xb6\xad`\xdd\xca3o\x00\x8c\xafM\x05\
-0\xceJL\xc9\x03\xe4:\x05\x8e\xa9,\x7f\xbf\xafk\
-\xc2\xb6\x97\x13\xba\xb3\x04\x0a\x12K&\x13\x1d\x1dp\x9e\
-\xc5\xd4\xbe\x13\x8ad\x0c\xa3z\xc7?Q$\xac\xaeB\
-\x06\xad\x11\x11\xac\xef\x9c\x96:\xe0\xd8\xdbS\x18\xd8\xaa\
-\xc8l\x14n\xf2\xb3\xb3'Qn\xd4\x02c\x8cf-\
-m\x8e\xdb\x96\x95\x88\xd7\xb1\xa6\xa2 \x9a\x11\xb1;\xc2\
-~\xb8B\xb0\xa6\x9fEEt\xbc\xb4\x18\x93;F\xac\
-\x0c<\xaaB\x1f8C\xc7\x84W\xd6\x02`\xf1rS\
-\x8a\xd7QOb\xe4~dxkO\xcbi\x15\xcez\
-\x92E+\xe5\x86\xc7~P\xb3\xa1\xefm\x88\xd9\x9c\xe1\
-x\xd5\x07\x09=\xbdp\xab\xde\x09b$\xacg\xb0H\
-\x95\xa1X\x0f\x05(\x95:@[\xe6\xa4\x0f\xee\x85\x22\
-\xb1Z\xbb>'#\xd6:p\x7f0=2zB\xa0\
-\xac=\x9d\x80p\xee\xa9\x8b \x88\xc8\x9e\x22\xc1)x\
-L\xd2\xe8\x8c\xb1\xfee\xf1\xb8* \xa5\xf5\xaed\xbf\
-\xe1\xe6\xe0\xfbS2\xd3\xdb\xa0\x7f\xafvZ\xfb\x98\x8e\
-\x89\xb3)\xe0\xa8\xbd\x8b\xe0\xe6P[%u\xaeS\x91\
-?\xdc({\xcaH\x8aT-e\xe4\xaf[\xbc\xccL\
-m\x0c\xd6\x9e\xc55\xba\xe2\x91;;\xcd\xe8\x0d\xb6\x83\
-c\xee\xd1(\x8c\xc2\xa0\xf7\x8e\xaf\xeb~\x12\xd6J\xed\
-\xf8\xf2\xbe\x03\xe0\x0a\xc8ZN\xb3n\xcb\x98~P\x8c\
-\x16\x07f8\x98\x13\xcd{\xe8\xf7<\x12\xd3I+\x06\
-5\x94\x85\xc0}M\xe7j\xc2)\x05\xf2q$\xa4D\
-\x1b\xe6m\x99p\x99\xad0\xb7\x19\x16\x16S\xf4\xe7Z\
-\xc2\x19\x83\xdb\x95v\xb9\xa83u\x99\xbcB\xb6\x182\
-\xb6\xee\xf9$\x8e\xae)#\xe5\x8e\xc7Vx\xe6\xe8\x1d\
-5\xe0\xaf\xdbv\xee\xaf\x8ds\xe7Y\x95s\xc1}\xcd\
-\xd8s\xc5\xb6W\xc6\xeb\x8a\x96Gx\x8cR%\xc1u\
-km#a\xd2\xa0w\x8b\xc9\x07\xcc\xde#8\x8f\x8f\
-m\x03\x0cp\x9d'l\x890 \xeb\xa0\xd5\x9al\xaa\
-\x85>\xf8]\x97~\xa9\x0d\xf7=\xa1\xb6gz'\x93\
-S\xb9\x07\x9f\x95]\xcf\xf3w\xa0\xd6\x9b.\xc4\x8e\xbd\
-\x14\xbc,\x13\xe6\xe8\xf0\xd8\x0bRm\xd8\x0e6\xa4\xa9\
-\x0c\xd8\x96\xc5m\x22od\xd7Z\xabv\xc6M\x7f\xb9\
-'X\xa1\x8e\x81\xce\x0c\x9b\xae\xa9\x8bV\x96\xcb\x1cp\
-\x1c\x05\xff\xe6?\xf8#\xfc\xed\x9f}\x83U\xda\xa9\xd7\
-\xdb|:\xba\x86\xae\xe5cM\xcf\x22\xa0\xe1$N\xee\
-\xb9\xd0R\xb9\x04,\x91\xab\x84Z\xb9\x12t\x86\x976\
-\xe0\xb0\x1dU\x81m\xee\x0c\x08\x9b<\xd3\x17\x9d\xe7s\
-l\x94J\x0a\xc8\xea];\x1e\x87\xac\xc4\xc2\x1f\xa7\xcc\
-\x90\xaeebq\xb9\xee\x05!:xYH\xf7\xfd\xc0\
-Q\xc3o\xfe\xda\x05\xc0\xeb\xb4\xdd\xbb\xa0$Z=\xb2\
-;\xf3\xaa\xd8\x8d9\xc9i\xadrG\x5cr\x95\x12r\
-\xb0\xe0\xc9\x00\x0f\xceK\xed\xc8q\xa45dJ;\xef\
-\xd1\x9a\xc1![Y\x07\xa7\x0d\x1d\x14\xd1\x1d\x89\xc1*\
-\xd6\x0e\xe5\xa7\xc3u\xe1(\xd1Y]\xe0\x9d\xd9\xdc)\
-3p'+x\xc6[\xaa(\x19\xbabND,\xed\
-2V#h\x89\xc2\xba\xc12\x1bx#\xd5i\xa1-\
-\x07\xe0\x8eu\x80S\x06\xd7\xbch2\x12\x83G\x0c\xac\
-\xc4\xd7\x83\xc4,\x80#\xefQD\xe4\xda\xf5`P\xd1\
-\xff\xf6\xd8\xb1\x1f\x034\xe4T\xc9\xf3\xef\xfe\xf9:a\
-\x99\x19\xc5\xd9\x1d_\xc61\xb9(\x85\xfb\xebR(\xea\
-!\xdc\x87/\x0b\xb9\x05\xb2\x5c\xf6\x8a?\xfe\xee\x82\xe0\
-\x1d\xb6TN!\x1a\xc9r\xfd\xdc\x89\x99f\xcf\x08\xde\
-\x91YP+N\x00R7tn\xd0\x0f\xedp\xbdL\
-g\xf8\x92\xf7\xfc\xce\x8e\xa3\x02\xee\xe9^h\xea\xe6\x8c\
-e7\xb3\xe9\xfb\xe3\xe8\xb1\xc1\x18\x87\x5c\x88Q]\xc5\
-\x02p\x16\xf0\x81p\xa4\x11g\xc9\xdc\xf1v\xee\xe6x\
-\xa0Q\xed<\x08\x90\x1c\xcd\xd3\xa7\xfe\xb1\xa6se0\
-\xb2\xbd\xb9v\xe1\xcb>E\x89\xd8,\xab\xe4\x01+Y\
-b@\x08\x9c\x9c\x5c\x97 \xec/\x14\x0f[\xb1\x89\xc6\
-\xc6\x0b\x9eX\xd5\xe8\xc9\xc6(\xf2.\x0fO\xf5i\x0b\
-\x0c\xee\xec\xe2r\xed0\x8e\xe9|S\xa4\x96$\xa5\xc1\
-\x9c\xe3z(\x15v\xe3$\xe5Y\xe9\x198I\x9b\xe7\
-\x80n\x06\x8b\xde\x9e\x9d2\xbf+\x8e\xd6\x0dpr4\
-\xb6\x83]\xde\x14\x14\x06S;\x0f=\x8d\x99\x8bX\x19\
-\xcb\xa4\xcf\xb81\xde\xd5\xc2\xf2?w)\xe7\xf5\x9c\x1c\
-\x12\xef9\xc7\xef\x93L\x82\xc61\xb8\xb0\xb9D\x04\xab\
-\xeb\x9e\x14\xa1\xd7+\xbcq<\xa4\x0c\xf7\xd7\x87\xa6j\
-\x90\x98q\x0a\x9e\xecz\xb9\x06\x92:F\xe3\x1c\xae\x97\
-\x80\x108rw\x06\x98g+\x94u\xc0\xcbe\xc2q\
-po?\xb9\xa7o\xde9\xae\x0a\xbf}\xb9\xa0\x83T\
-\xb5\xbf\xfa\xcd;\x05\xb6\x8d:\x83\x9c\x1b\x06\xb6#\xe5\
-\xc2s\x09L\xff\xeb\x1dx\xac\x15\xf3\x1485\xd3\xee\
-\xbd\xa3#*\x83\xe3\xbe\xf1\xd0'\xe8I\x0a\xfd\xe8I\
-\xb5\x13\xb5\xd0\xb9gNG\xed\xa4\xa0VY\xd1\xbc\x5c\
-\x05\xb5\xf5\x13\xd0\x04\x00\xefk\xc6\xdbz\x9c+\xc2\x94\
-2.K8\xa3{[\xa7\xea\x9c\x91\xd0\xa33$M\
-.x{6XC\xe7r]\x22\xe6\x18p\xbb\x04\x1c\
-\x9a\xb0\x8d\x82\xe8\xa6\xf8h8\xea4\xc6\xbe}XU\
-\x19:%6Jk\x8cU\xc4\x004\x15\x15\xe2\x9cB\
-\xdc\xb7\x03\xad\x93\x05\xf3W\xbf~G:*n\xcb\x93\
-D\x1a\xbd\x97F\xc5\xc1j\x9c\xfd\xbaL:\xa7\xf8c\
-l)S\xe1\xef\xf8\x19\xef\xb9\xd0\xff\xdex\xae\x1f\x99\
-V\xeb\xcf\xd7\x99\xc4D\xd1\x06c\xa0\xfb\xack\x9f\x7f\
-\x9d=R\xeej\x009U~\x1c\x19Y\xc0\xb4K$\
->\xddXr\x19\x86\xe5\xda:\x83-W\xfc7\xff\xfe\
-\xcf0O\x11>:\xfc\xc3\x7f\xed\xa7\x02\x1e\xa9B\x02\
-\x1d\x05c\xb54\xd0\xc3c\xa2\xc6i[\x85u\xbc\xf4\
-\x93&oKt\x08\x81\x22D\x9e9\x0d\x97\x8b\xc7e\
-\x89't(\xe7\x86\xf5h\xf8\xfc2#\xba!\x88\xe4\
-\x87\xf3z\x09\x88\xce\xe2\xa1\xf5\xcd\x96\x8a\xfew\xfe\xbe\
-'\xad\xb9\xe2<\x1bc\x98p5\xbf\xbe\xff\xb5\x0b\x80\
-\x8fzy\xcf\xc7\xce\xccig\x91+!\x06\xeb\xe3y\
-\xd1\x1d\x83E.\xe1\x9bu\x06o\x8f]\xdd[W\x84\
--p\xdfY=\x1d\x99\x9d\xcbHCjj]Zg\
-\xb8\x0b12\xea\xf8-\xab\x9a\x94(>\xdb\x8e\x02k\
-\xba\x94\xfc\x0a\x00\xa9\x8cy\x94P\xfe\xb4\xc7U\xf9\xd6\
-[\xa3\xd8et`1\x00\xf3\xe4NQ\x88\x01p\x9b\
-\x02\xbb\x97:\xd8\xdf\x9da@\x8e\x94\xaa#\xf7S|\
-\x01\x81Y\x86x%x\x9c\x22;\xef\x1d\x19\xeb\xa6\xcb\
-\xa2(\xc8Op\xb8\x9f\xd5\xbc\xc5\xed2\xe1:\x07\xec\
-\xb9\xf0sP\xb0\x8a1V{\xb1\xaexU^\xd4\xee\
-L\x95S\xaco\x80\x84j\xec\x82\x823x\xbf\xef\xd8\
-\x046o\x9d#\xb69\xf2\xf7\xf4\xd6J\x98\xc8\x10\x1e\
-~\xe6\x0e\xf3\xcc\xaeyX\xb1\xe6`\xb1\xa7JH\x10\
-\xcc9\x9e;\xbb\x12\xa5\xa0\xdd\xd7\x82\xa4H\xd2\x97[\
-D\xb0N\xb1\xb5M\xbb9\xba.\xaa\xec4\xdc\xf3Q\
-\x14\x054\xf2\xdd\xab\xd1\xa1\xc35\x0d\xd3\xde\xd4\xcdv\
-~\xe6U\x05\xcf(\x82|p\xd4\x12\xd4\xa6I\xc38\
-\xc7x\x98\x0c~\xfc\xfb\x9d\xc9ZN\xe8\xd9\x5c:\x0e\
-A1\x1fG\xa1&%\xf1\xd2\x8ba\xf8\x96\xf9\x82\xe6\
-$\x0c\xad\xa3\x22\xfc2{=\x9fZ\xd5t\xeeNG\
-VA\xef@+|\xcer\xabB\xfa\xb2\xe8\x09\x81\x07\
-\xf6\xba\x15\x8a\x92:\x05G\xa57\xd4B/~\xa9\x1d\
-Q\x9e\xfa\xf7\x95\xfe\xf9 4,\x81F\x14\xd1M\xce\
-b\xdd\x9b\x04p\x1d\x97h1M\xdcc[\xa3Q\xbd\
-W\xb7\x0f\x85\xc78\xea.\x92l\x8a\xb96 ]=.\xd1\
-\xa3\x08\x1f\x9a\xdbP\xfb\xf73\xaa8\xd5\x0a\xe3p\xda\
-\xceb\xd4\xa4\xc5\x91p\xc6\x98Q\xba\x09\x1c(z\x1a\
-z\x05\xba5\x9e\xecx\xa3\xe9L \xe3\xe5?\
-s\x9d\x85\xc0u\xb5\xd8\xbc\x95\xb1\x97\xc7e\xf5@\xe3\
-\xac\xd9\xcb\xae\xcejN\x14\x8c\xb6\x93\xaee\xadF\xad\
-\x0d\xbdi\xa4\xca\x8bf[,\x9ed\x9f\xa4\xd5#\xd0\
-\x81Iz\x92T\xd8\x81\xd7\xfd\x04\xba\x82V$d)\
-\xe9N\xb2\xac j\x97l%4\xeb\xd63\
-k\x18)\x1a\x82G\xab\x19\xf3dPJA5TR\
-\xd7\xaa\x84\xa6B\xb1\x17r\x03\x0c\xf7\xfa.\x9ba\xe5\
-3\x96\x97\xc8\x11\xb9'\xaa\xad\x01\xc8\xea\x86\xed(2\
-\x82\x0d\xc85cU\x0c\xf0vF,\x12y\xf8\xca\xea\
-{O\x19\x00\xb1\xc9ar,v\x84\xb4\xec\x07\xe8\xcb\
-:\x0d\xac-@\x1f\xe9\x91\xa8\x86\xb5\x8b\x81m\xc0v\
-\xb0s\x8c\xb9\xe2\x00w\x8d\xa6\xf2\xf3\xe1\x1e\xc9\xc9\x97\
-\xbe\x10\x80\x93r\xc7\xd2#\xe6\x8c\xeb2k\x9d\xc2]\
-~)\xef,\xea\xb3%\x18q\xfec\xc9T3[K\
-\xa7@2\x84\xa64^\xf0\xb5\xb2\x1b\x9c'\xaf\xa2\xc4\
-\x8cT\x8d3U,\x86\x87\xe63F\x5c\xb4\x97>N\
-z\xda\x93,\x900\x84\xbcx\xd7\x14\x9aB\xcf\xf4\x14\
-H\x1f\x9c\xbc\x1b\xeb\x02\x12 -\xce\x93\xe1?\xdd\xe3\
-~J\xb0\x963\xc6\x04\xc8L\x146\xa5\xdc\xf0\x17\x7f\
-\xf4\x13\xb4?\xfa\xa9\xaa\xf2\x88Z\xab\x80;\x0d\xab\xed\
-Y\xf2\x09\x9fn\x8b\xc4\xa9uX\xd9(\xdc2x\xec\
-t\x96<\x22C\xa7r.\xf8\xf4aQt.\x8fL\
- \xcb\x8b_\x06 \xca\x8b\xa6y\xa6\xcc$M_\xe9\
-\xffn\x0e\xd6\x00\xcf\xed\xe4\xd0Kc\xfe\xc9{\xc4\x93\
-\x1c\x03\xef\x94\xbaW*\x82aG\xd3\x13\x12_ot\
-\xd9\xa4S\xb7\xee\xc0\xba\x02g\xe2\xe8\xf7\xcb=b\xf2\
-\xfc\xe7\xf8\xbbS\x9f\x03o\xb1KTe\x00\xb4bp\
-{\x99\xc5J\xcf\x12\xcc\xb22\x9b&\x0b$r\x16\x9e\
-;Iu\xb9\x92\xcc\xd6LS\xe1o)\xd4\xcbE\xdd\
-&\xb9\xee\xeb2\xe1@D\xf0\x011'\xae\xe52y\
-\xe7\xd7uB\xae \xdd\xf9\x5cR|\xd9\xa63!\xa5\x8a\
-\xe7}\x87\xb7\xc2Jk\xef1\x1a\x8d\x19t\x8ekJ\
-\xc7\xc7\x97D\xc4\xba\x19\xfa\x98\x87U\xf6\x14B{p\
-U\x98\xb9b\xe0]\xab_\xb5\x0f\xf5W^\x00\xfc\x9b\
-\xcb\xbf(\xb5\xd6\xea\x1d)lUJ\xef\x97{\x1a\xd9\
-8(\x95\x8a\xf0w\x97\x05\xad\x01\x1fo\x07`\x01\xd3\
-\x81O/\x07\x92\xa0\x09\x85=B\xb5K\xf5\x81\x1e\xb4\
-=\xd1\x92\x94q\xdb\x13\xce\xdc\xf8\xc6\x9f\xc4\x85>\xdf\
-\xf2\x0c\x90Y\x9c\xc5Eb\x89\xa67xO\x0d\x17\xc5\
-R\x1acxc[2\x95[\xa7\xaa\x19\xb2\x15\xb2\xad\
-\xa4\xd6u\x1bAA\x96\xd1\xb5z8h\xa3\x8a\x12\x98\
-QK`-[\xd5\x0dM!\x1acq\xeb\xe8\x15x\
-zZ\x99\x9e%\x22\x5cVRZ\x91\xfd\xe8\x8b\xf7\xcb\
-\x9c\xcd9/\xeb\x9e~\xfe\xda1cd;\x80\xa7\x0b\
-q\x9e\xb5\xf6W\xc18\x84\xba\xdc\xf6\x84R+\x9c\xa1\
-oz\x8b\xc4\xd9^\xd6\xc8 \x8e\
-:O\xc3\xb5\x11\x88\xe1\xbc\x9f,s\xb5\x1a\x14\x0a\x04\
-Y\xbdh\x1dd\x0a^\x851\x0d\xceQIK\x8b\x1d\
-I_\xadq\xc3\xb7\x86\x94\xb5q\xba\x04\xa8\x0592\
-\xb1\xc6\xa3\xe5:B`\xbc\xc3l\x8b\xbd\xdc\x13\xbe~\
-9\xd8\xde/\xe5\x01TZ\xc3d9\xecB\xe0n\x91\
-\xb6\xcc\x94\xa8;xw\x0d\x801S\xad\xdb[G\xb4\
-T\xd5\xf6\x8a9\xa7\x1b!Ic3\xaf\xd2\x0eP$\
-\xe7\xb1\x860\xd5\xe2\xc6\x18\x04cpOE\x84I\x01\
-P\x8ch\x97*\xf4\xbcZ\xe2\xf7\xfdD*\x19\xd7%\
-\x0a3\xcc\xd6\xac\xb1\x16\xd6:AQX\x80z\xfb\x08\
-\xfaq\xd6MN\x81\xd1g\x9a[\xd7I0\xcf\xcfc\
-\xb8\x03\xb6\x95\xdd\xa1\xa7K\x94\xc8\x8d\xf7\xec\x1a)\xae\
-\xa2\xa5\xa9O\x9b\xe88m1\x0f\x9d\x05\xc38\xd9\x06\
-\xe7\xa7\xab\xc0\x82\x96\xa4\xa1\xa2\xae\xd2\x89\xac\xab\x97\x08\
-\xd8\x09\xf5k'2\xdbX\xd2\x17\x83%\xf0\xa4\xcf\xee\
-\x1e\xef\xefu\xe5\xc6x\xbbg\xa4\x9cg\x02h\xab\x04\
-v\x11\x12\xc5\x83\xc3\xcb\x9eH\xdd+m\x22\x9a\x1f\xc5\
-9\xbb_0\xec\x0c\xb2{\xc4qH\x0cli\x1fg\
-\xc1\xcb\xbdL\xa7\x88Q\x0b?j\xe3\xb1\xd6 Z\x83\
-{\xa2\x05o\xf1\x16\xd1\xb2\xb0n\xa3\xd5\xae\x83\xc1Y\
-x\x10\xf0\xea\xf2y\xfd\xccI\xcc\x89#\xe5\xc9\xd2\x1f\
-\x1a\x8d*=Q\x0c\x8f%x\xb6|\x85?\xaf\x8d\xb9\
-\xf0\xde\xb9\x19l\xe5\x8c\x97\xf0\x90\x10\x9a\x22\x82)A\
-J\x09\xb9v\xac\xfeq\x92\xf4\x91]\x86\xde\xba\xe8q\
-El\xff\x8a\xdb=\xe3\xe3\xfd\x98\x0a\xf8e\xa1f$\
-\xb7\x86k\x8c\xd3\x0aj\x00\xbc\x7f\xb7\xa1B\x10\x9c\xda\
-\xc4\xb9\x1f-m\xa2\x7f{\x03Lw\x13n\xe3\x83\x11\
-I3k\x94\xc1\xfc\x05/<\xfcx3\x86`\xf7\xcb\
-\x8fw\xfc\xb3\x7f\xf1S|\xfd\xb2\x03\xcdL\x90\xd2\xb0\
-22\xbb\x82\x85\x99\xf3\x1c\xb3\x0eM\xcb\x9e\xf2\xc4\x04\
-\x07\xcf\xc27F\x87\xeb\xeaQ\xf2\x08Dc\x1a\xe0\x18\
-1FG`[.\xec>\xfe\xd5\x1f\xfd\x10\xff\xc6o\
-\xfd@\xfbU\xc7'\x15\x19\xde;\xa4\xcaM\xf7,\x99\
-\xc1]\xb9\xe0\x8f\xff\xf4\x13J.\xb8\xed;jm\x88\
-\x1a5{K\x0d\xc3\xba\xb2\xc8\xdfV:L\xa0\x0e\xe6\
-\xd8OFf\x89\x81b~[\x11\x9bB\xee3\xe3\xb0\
-\xad\x01\xce8v\x08k\xc3q&\x89*\x01X\x07g\
-\x5c\xfb\xed\xcb\x1f\xff\x1aP\xc0\xf5\x1f\xf7\xa34U\xe6\
-\xa1\xd7\x8e\xeec\xe81\xfa\x9ej\xe9\xd6\x98n\x8c\xeb\
-\xc6\xa2\xe7\xd6\xba\x8b\xa6\x97\xda\xfa\xcb^\xfaYj\xa7\
-\x18\x877\xfb\xaad\xae6\xbc\xc8\xf2i&\xa9\xe9s\
-)\xb8^\xa2lL\x85 \xf5\x5c\x83\xd4\x98\x01j\xa1{\x90Z\
+\xd7\xc9\x99\x9d`\xce\xb3~\x1fu\xf7M\xb4\xd6\xf3>\
+\xcfm\xb3\x80\xc6^\xc1u@C-7:\xb0>\xd0\
+\xc7\xab\xe3\xf6rL\xee\xdb:\xe7>M49\xc4\x06\
+}\xdf\xa6}\xc9'\xad\x19\x7f\x00\xc8\xd0\xf6\x88\x80q\
+?\x98\x9b^\xd7\x83}R\xc7\x0b6-P\xb3\x0e\x1f\
+j\xed\xc1\x99`\xce3\x81\x19\xbc\xc193h\x81\xb8\
+\xeff\xab\x07z\xbc\xcdyH>\xcd\xa3E7\xd1s\
+\xech\xec\xe3\xbb\xb5\x93\x9fI\x1f\x8do\xcf9\xee]\
+\xf4\xda\xd7\xd87x.\xb7cz\xed\x87f\xc2={\
+q\xc0q\xe39\xdf\xd3\xe7\xb2\xc6\x07\xb6\xaf\x85?\x1b\
+7u v\x1f\xbc#\xf1\xe4\xd1\xf3]\x0f\xf6I\x1d\
+/\xd8\xb4@\xcd:|\xa8\xb5\x07g\x829\xcf\x04f\
+\xf0\x06\xe7\xcc\xa0\x05\xe2\xbe\x9b\xad\x1e\xe8\xf16\xe7!\
+\xf94\x8f\x16\xddD\xcf\xb1\xa3\xb1\x8f\xef\xd6N~&\
+}4\xbe=\xe7\xb8w\xd1k_c\xdf\xe0\xb9\xdc\x8e\
+\xe9\xb5\x1f\x9a\x09\xf7\xec\xc5\x01\xc7\x8d\xe7|O\x9f\xcb\
+\x1a\x1f\xd8\xbe\x16\xfel\xdc\xd4a\x9b5\x97\x7f\x07\xc0\
+\xe6!1\xb95'\xd2\xc7\xc7^\xd3\x1c\xba\x13=G\
+\xee\xdb\x1e\xbd\x97\x98;zf[kRG\x17z\x8f\
+i\x1f\xe2I\xef\x9a\xfdS\xf7\xdb\x1c\x87\xf4\xb7Y\xc7\
+\xa1\xe7\x0c\xbd\xae\x87\xf4zG{\xd3\xa7\xde\xfdG\xb1\
+O\x8e\xfd\x13\xb7?\xf9\xf4~\x83\xcewf<7y\
+\xa0\xf11\x9d\xc3Vo\xfa\xf3\x80w\xb5W\xcf\xd0\xdf\
+>\xa3\xf1\xec\xa6K\xbcyn\xa4\x8f\x8f\xbd\xa69t\
+'z\x8e\xdc\xb7=z/1w\xf4\xcc\xb6\xd6\xa4\x8e\
+.\xf4\x1e\xd3>\xc4\x93\xde5\xfb\xa7\xee\xb79\x0e\xe9\
+o\xb3\x8eC\xcf\x19z]\x0f\xe9\xf5\x8e\xf6\xa6O\xbd\
+\xfb\x8fb\x9f\x1c\xfb'n\x7f\xf2\xe9\xfd\x06\x9d\xef\xcc\
+xn\xf2@\xe3c:\x87\xad\xde\xf4\xe7\x01\xefj\xaf\
+\x9e\xa1\xbf}F\xb3\xed3\xeb\x0f\x00\x81\x87aD<\
+-\x0b^h\x1d\xdam\x16_p<\xed\xd9\xe8]\xc0\
+^j\xbe=\x13\xe8m>\x8dk\xedc\xafi6t\
+oz\xcb\x86w\xc0\xe6\x15:\x0f\xd4&/8y\x06\
+\xfa\xf4&M\xb3\xbd\xa5\xeb\xc9\xbd\x7f{c\xd8t\xa7\
+]\xd1\x9d\x7f\x03\xe8\xe5\x8d\xc7,\
-Qu\x07\x1b\x99\xe0\x8c\xb8\xf3\xfcy.r\x5cm\x8a\
-\xd5e\x81M \xd6u\x89z&\x18\xda3M\xc4\xb3\
-G\x91\x137u\xfdk*\x98\x9cD\xa2\xc3>\xab\x95\
-\x5c\x11\xea\xb9vN\x13\x9d\x1a\xa9\x94\xab\x0a\x02\x12\xf5\
-\x9a\x12H\x9b&\x82\xb5@\xf1\xd6\xfc\x0c\x08F\xa36\
-\xc29\x8e\xf9\xe6`\x91\xf33\x9dt\xcf\x15N\x16\xca\
-=\x15\xea\x1d\xc4\x9ch\xbd\x13\xf0\xa6\xa9\x84\x01\xb0,\
-N\xa1D$H\xbe=\x0e\xfc\xf3_\xbc\xa3w>\xab\
-\x8f\xfd8\x05\xf1G\xcap\xde2\xfc,8\x18\xc7\xa2\
-'\xf7\x86\xfb\x91\xa5\xbf\xa0>\xaew\xfe\x9a5\xb3A\
-\xf6\xde\xb1\x10w<\xf7\x979\xf2\xec\xd4:\xb0W\x83\
-\xe8#\xbe\xbd\x1e_\xfe\xc6\x0a\x00\x93\xbe<\xd0-\xf6\
-B\xc0\xcem\x9e\xb8\xdf\xa8\x0d\x0f\xe5f[\xdb\xce\x0e\
-\x99\x81\x1d\x16[\xce(R9o\x07}\xea\xc3rv\
-\xdfH\x98\xdbR\xd1_\x98\x17B\xf0\x0e\x93\xb3\xd8\x0e\
-z.y\x09\xd3#j,\x0f\x8d\xdb\x1c0y\xfa\xa8\
-\xe7\xd9\xe32\x13K\xec\x07v\xccRu~_\xcb\x09\
-\xa0\xf9X\xf3YU:\xeb\xb0\x0d\x11\xd0\x18\xf5\x9a\xaa\
-U\x86U\xf7H\xdd*-V\x83\xf2Go1:U\
-\xd8\xe3B0\x86q\xb79W\x1c\xa5`K\xbc\xbc\x9a\
-|\xe9c\x17\xdd;\xb3\xbf\xd7\xbdr\x0c:O\x1a\xb5\
-k\xff&\x81\x9eQ\xc1s\xdf\xf9\x195\xf4S\xc3\xe0\
-\xa5\xaa.\xb5bO\x85\xdet\xed\xb9\x8d\xd4\xad#\x1c\
-hD\x0b\xd3%\xd1\xf53v\xa9\xe3\xa1\xc9\x04aB\
-Y~h\xa8\x8a\xdeE\xe7\xf3\xdeH\x19\xcd\x9diW\
-\xf1\xb1D'B\x17=\xb2\xc1Q\x81\x1b\x9d}\x12\xc9\
-t\x81/RpWHT\x07v\x9fPA\x07\xd3E\
-#c\xba\x19\xc0\x91'\xa77\xf6tV4\x0d\x81_\
-\xae\x91\x1dl\xadp\xbe\x9f\xf4\xad\xaa\xa5_\x97Ow\
-\x14Kz$\xce\xe9R\xd5\xbetd{\xb3\xd3\xd7\x8a\
-@{\x7fo)\xf8\x1aEDk\x9c\x9f\xb4\xc6\xd1\xa9\
-\xd5!U\x81\xd3\x892R\x0c\x87\x15y\x14\x1c\xfb\xd1\
-`\xe1N\x91\xdd\xb7\xaf\xd3\x89\xa2\xae\x1d\xb8]9\xfa\
-\x1f+\x9eaW\xea\x1dx\x7f\x0c$)\x7f\xf6\x06v\
-\xe4/7Be`\x0c\xae\x97\x80ibg\xeb\xf5\xfc\
-8kp\xa4\x8c\xfb\x9aP\x1a\xf5-E\xc0\xa01\x99\
-\xe2g\xc3\x0e|\xd3{\xec--_\xb56a\x81\x95\
-\x17\xef\xb5\xf6+P\x048\xdf\xab\xcb\x1c\x95\x9b\xc0\xf5\
-JkT\xe0\xbf.\x13CxT2\xa5\x5c\xceX\xe7\
-\xbd\xf0\x90\xee\x8dbD\xa6\x0e\x0a\xed\xaa\xcf\x0b\x80.\
-`Zm\x1f\xfb\x8e\xfbV5jg\x1e\xfa\x18\x0d?\
-\xd6\x04\xa7y\x7f.\xc4:\x87\xc9#X\x8f\xf7\x07m\
-\xa2\x8cb\xae\xb2_qZ\xb2,\x01\xb7%\xe2v\x0d\
-R\x85\x03_\xef\xd4fx\xad\x05\x8d%s\xc0Z^\
-\xe4\xde\xd1\x228M\x0e\xb7)\xe22E\x01\xb3\x80\xcb\
-\x1c\
-[>\xd6r\x8a\xb28=`\xde\xf64S\x10w\x9d\
-=^\x16\x8fO\xb7\x08\x03r\xa0\xd9\xd1U\xackV\
-\x87\xe7p\x7f\x14\x1e\x18N?\xab$\xd0\xa9\xd438\
-\xe6\xc8\x95\x0f\x8e\xe5\x0a \x8bm0DpS\xf0\xb2\
-\xde\xf1\xe1\xbb\xceT\xefG!_S\xa5\xb0\xae7\x8a\
-o\xac\x12\xc8v\xa9\xf7\xd7\x95\xfa\xd1R\xaa<\xd3\xea\
-\xec5\x91H\x89\x8awvc\xe6\x8cW\x1e\xd8Sc\
-\xf9\x92\xefB`&U\x9f\x5c{t\xed\xd2\x99t5\
-\x05'\x22#\x0f\x98\xa3<\xc7\xd0\x9d\x0bt\x1c%+\
-y\x8f\xdd[\x91\xf8\x8e\xdc\xebL%l\xaa0\x9d\xe2\
-0\x86\x08\x99S\xd0\x13\x04\xbbq\xc6+M++\x86\
-v\xe8(\xa8\xb5\x88\x8eq\xd2CHH;N?w\
-\xdeV\x85@J\xd4NT\x15JT\xe7\x92\x7f\x8f\xc6\
-K\xf4\xbee*\xcc\x9b.\xefN\x91\xe6<+\xa0\xa6\
-\x8e\xef\xac\xe3v\x99\xa8\xf5p\xb4\x0d\x16M>\xe6H\
-Aj)\x05[\xc9\xf4#+\x17\xa2vv\x15\xeb\x9e\
-\xb5\xce\xa0_\x9d\xcf\x1f-q\xf7Gf\xbc\xf2D\xf2\
-\xdd\xd8\xc5\xee\xa9b\xddT\xf4\x01x\x7f\x1c\xa2n\x8a\
-\x80\x18\xa9\xce\x9e\xa2\x1d\xb0\xc0\x1f\xb8q\xf8c\xefI\
-y\xe8f\x8c\xcby\xd8\x92\x06\xe7\x15E\xcbH\xd2\xd6\
-9vo\x9d\x17\xec2\x11\x18\xd3\x14\xe9K\xfaf\x82\
-E?'\x14F\xf6\xd3\x949\x15\x99\xa2\xc7m\x09p\
-\x8e]hS\xb1\x90J\xc1\xbe\xd3E\xd4\xa4\x13\x9a'\
-{:R\x86\xce`\x0a\x1e\x17E\xf3\x1e\xb9\xe2\xebG\
-\xc2\xdb\xe3\xe0\xaf\xc9\x5c[p\xfcL\xdf<\x8b\xad\x86\
-\xeb\xec4\xb5P\xc7+\x85\xfe\x12\x1d\x96@\xc5\xf4~\
-0\xdc\xa9\x8c\x0bS\xc0\x9b-\xd7\xd3*\xb9k\xbf>\
-\xe2\x80\x8fTa\x1d\xe8u\xaf\x141f\xe9W`\xf8\
-w\xcc\xadk\xb4\x1f(&\xaeP\xd6\x06\xce\xa2n\x8a\
-A+\x05\xcb\xf0\xad)\x08~\xc3\xb5\x86\xf3\x16)\x8d\
-)\x12\xe3v\x01+\xc6\x05q\xc4wa\xba\xbdU|\
-s-\x0aOK8j9E\xc8\x1f[\x92+\xa1\x03\
-\xa6\xa9\x99\xf3\xb0\xc6\x9ez\xa4\x5c\xb8\xa2Z\x82\xa3X\
-;ZM\x10*>v\x8a\x85/\x12\xa9\x01\x06\xd7e\
-B-\xc3\xf2\x97\x84I\x1e\xcc\x96~\xb2\x19\xb6\xbd \
-\xa5,O\x7fCN|\x8e\xbc\xd27\xe7\xc9\xe1:\xfb\
-S\x17cT`\x06iZ\xf6\xc2\x86\xa8w(\x82\xbb\
-\xe22\x07\xdc&\xa7\x90\xa5\x8aevx\xbd\xcdp\x9e\
-\x90\xa9#W\xbc^&\x00B)\x1b\xae\x05\xa6\xe0\xcf\
-3w\x89\xbc\xdc\xbb\xe1\xb9\xf6g?\x7f\xc3\xc7~\xe0\
-v\x09r\x82p\x22\xe4\x9dC\x1c\xce\x0b\xeb\xf0\xb1\x1f\
-\xa8x\xba\xb4\x8e\x83S\x90\xa2d\xd8\xcb\x14\xb5\xc3g\
-\xca\xec\x963\xde\xd6tjD\xd6-\xa1\xc3`]\x0f\
-|l\x05\x06\x0e\x9f_f9\x18\xf8\x99\x0dw\x92,\
-\x12\xa7>j\x047\xfd\xe9_}\xc1?\xfe'\xff?\
-\xfc\xe3\xff\xdb\x9f\xe1?\xff\xc5\x1b\x1a\xfa\x89;7X\
-\xfe\xa0\x02\xe0\xf7\xa2\x80\x01`\xab\xb7\xb7\x18;\x96\x10\
-1\x07\x83\xc7\x9e\xf1rq\x18\xfb\x80u?\xf0\x1af\
-\xf8\x89\xe2\x11\x8e\xdd\xb9\xe7\xad\xad\x9d\xe2\xabi2\xd8\
-w\xa2{B\x00\xfe\xf2\xd7w\x5cg\x8fo>]\x90\
-\x0bG'U\x7f\xd1\x09\x0e\x09\x14;\xf5\x06d\xd0w\
-}\x99Iv\xa2\xe0\xcd\xa15\xe6\xd7w\xf9N(,\
-r\xf8\xd8\x0e\x5c\xa7pN#:\x88\x0e\xbe\xce|y\
-{\xd3\x17\x97\x0a\x1f\xf8\xe8\xe0\x5c\x87\xc9\xb2\xd65\x16\
--_\xdf\x13mXJ\xd1K\xb9!\xe7|\x02]\xbc\
-\xf5P(\x14\x827x\xb9MH)\xa3d\x16\x1e\x97\
-\xd9\xc3\x1a\x87e\x92\xba\xf8\xa0\xc6\xc0;s\x16CA\
-\xeb\x8f-qWV\x1b}\xfbV>\xdaZ\xfb9\x0e\
-\x1a\x1c\x84\xa1p\x0d\x8e/\xa8\x95G\x9cjV\x8e\xed\
-\x06\x7f\x81\x95\xf9\x93\xb10G\xcf\x11\xae^\x1ck\x0d\
-\xa2\x1b\x89c,\xb6&\xefH+S\x0b\xb0\x1fD\xfe\
-\xd6\xde\xf08*\x8b\xac\xda0y\x8e\xfd\x86&a\x0a\
-\x06\xb5\x1a<\x0e)\xf1\xadWWH\xe6B\xed8\x7f\
-_o\x0dl\xb7(\x99\xa3\xf7=U>\x07\x96\xb6\xb9\
-\x9c\x0b\xf2^%\xf6\xa3Un \xa5_\xe6p\xfe\x19\
-\xa5\xf1{\x5c\x22\xc9i\xc1\xf12\xae\xb5b\x9a\xa81\
-\x19/\x0e\x80\x93\xef0\xf4\x02\x1e8\xc5Ud\xd3w\
-\xbc\x5c\x99\xb2\xd5\x00\xf2\xe3'w:\x5cz\xefXW\
-\x22i\xad\x8aZmO1E\x87^\xda\x09MZ&\
-\x8f#\xd1zuXs\xfe\xfb\xc6\x04\xd4ZE\xa4\x03\
-\x92\x0a\xd5\xe0\xec9%\xb9.\xfe\x9cZ<\
--,\x96\xb4\xcb\xef]\xaa\xfb\xe1\x81\xdf\x88\xc7\x8d\x1e\
-\xd2\xba\x14v\x91\xc1\x12\xf7\x5c\xba&T\xfc\x0c\x16\xe5\
-\xc53:\x97\x07-,\xc7\xf3\x8f\x83\xc0\x98$=\xc1\
-\xe8\x04\xabp\xa8\xb5p\x87IG\x08\xe0`'\xe5\xd0\
-HWr\xd9XL\x5c\x97 b#W\x18ow\x86\
-\x09\xc5\xc0\x18\xec\xa6\xe2\xdbZ#\xab\x93\xc3qP\xf3\
-\x13<\xa7p\xdb\x1aT\xec\xbekGR)\xbc\x9cJ\
-c\x87/,poP\x81=l\xab}\x86d\xc5\xe0\
-pY\x83\xc2\x8d\xfc\x0c9ba\xd9\xe0\x1dW\x87\xdb\
-\x1a41q\xfa\x1c\x0a\xden\xe48<_\x03\xb9\x12\
-U\xf6\xbd\xc5\xe3H\xec\xe6?^\x16,\x9e\xeb\x96,\
-0\xcbq\xb69\x11\x1c\x87\xf4C\x018E\xd1\xd31\
-\x00\xaf;\xcf\x0bo\x0c\x8e\x5c\xb1\xa72\x05\x81Kp\
-\x13aNnI\x82s\x06\xdf<\xad0\x86\x7fwJ\
-\xfc\xfb.K@\x0c\x0e\xb7\xa3prU:\x9e\x84\xee\
-\x8d\x22\x86\xf2\xf9#\xcf\x03\x22\xa6\x1egF\x95E#\
-X\x8f\x94\xa1K\x88\xd8\xe8\xebJ\xe8\xda\xf5\x1aH\xfc\
-\xf4\x0e\x7f\xf9\xdd\x1brf\xc8\xceu%\xdc+\x06\xae\
-h\xc9\x85`W\xba(r\xbd\x16Nm\xa2\xf3\xb4R\
-\x96A\xcf+\x0c\xb3\xb2\x9c<=\xe9\x22\x8db\xf2\x9f\
-gA\xaeE\xdc\x03\xcb\xb4\xcc\xd4\xf0\xeb\xcf\x0f\xbc=\
-\xa89I\xb5i\x0d\xc9\xf7\x98\x0e\x0a;\x8b\x9f\xaa\x97\
-\xad\x88\xd30\xc2\xc9\xbc:\xf1\xd1\xed\xa7\xca8mg\
-\xad\xb2.\x86\xd0\xb7\xcbJi\xb4\xa6\x1a\xb9!\xf5\x9d\
-DX\xd9\xfc\xdd\xcf\xac\x8c\x0f\xc7\xac\x09\xa1\xce\xfdD\
-\xdas\xeaf\x0d\x05\x8c0\xef\x14\xd4\xc7^\xd0`\xb0\
-\xa7J\x04\xbdu\xd8S\xc6=\x15%\x93v\xbc\xdd3\
-J78+\xcf\xab\xeb\x12\xe4\xba0\x02}\xf5\x89\x80\
-.\xa5\xcd\xa6\xb4\x94\x22`\xd3\xf89\xe84\xaa*2\
-\x87\xabj\x8d\x96\xda\x10\xcf\xc9\xd1yV:\x8aTD\
-\xbd\xedY\x22\xe6\xfc\xa3\x92\x00\x7fR\x01\x80\x12\xbe\xda\
-\x99\xb6\xc5nd$\xee\x0du\xfcu\xa3\xa5\x8a\x8at\
-\x92\x95\x96H\x0b[\xd6\xcb\xee\x8c\xc1\x16\
-\xe5\xdc\xaaF?\xb4\xfe]\xd6\xc8=\xaa\x03`-^\
-.\x91\x82\x18A\x94\xbdv\x89oGR\x0aSG7\
-\xc4\xc5\xa6L\x04l+}\xa2E\xcf\xc4\xff\xae\x89\xeb\
-n\x0cP\xa4\xc4g\x97B\x1d\xa8uD\xe8\xe6\xcc\xca\
-:\x97\x82\xcb\xfa>\xf24\xaaL\xcb\x80\x8c\x1cY\x1e\
-W\x034'\xd50=\xdaA6\xad\xde92\x0a\x9e\
-xI\x86\xb4P47\xec\x93\x8ca\x95j\xb9Q\x8f\
-\xe05r\xbe\x9f\xcc\x1e\xcf\x99\x7f\xa7\xb5\xdc\xf9]/\
-\x0b\x0f\xd3\xcc\xc8b\xe7\xcc\xcc\x94v\xda\x0f\x07\x05%\
-\xc5a\x074\x1c\xd7/\x8b\x9f$\xad\xe8\xbdR\xff\xba\
-\xba&\x0a<\xb9\xe7\xe5\xf3q\x15\x1f\x22KSQ\x07\
-\x88E8\xe8\x11\x13\xea\x0c\xff\xbc-\x06,r{\x9c\
-\xb9(7\x9dS\x11k0A$D\xb1\xf2R\x1c\x81\
-\x22\xd6\xc9\xeaTx\x91\x14\x8d\xbe\xad\xdc$^\xe0\xa5\
-\xd6\x89q>2\xf7\xddc\xc5e\xb5[\xa7j\xdfM\
-\x9b\xa5\x1b\xe8`o\xe7A\x16EM\x5cc\xe0\xfaK\
-\x17\xe6p\xa1\x9c\xea\x9eF\xf8\x0eG\x97\xc0\xdf\xf9\xc5\
-\x0b>=1&uh\xec\xa7\xb0\xd0q\xa4|\xdf\xe9\
-\xe3\xdf\xa2\x17\x84\x8a\xdfGt\xb4R\xb2Cw\x0a\x06\
-\xc1\x9c\x0c9M\xcd\x1e\xa9\xa8\xcb\xe5\x9f\xff\xb4E\x1c\
-\xa9b\xf1d[\xb4\xca\xefe\xf1~R\x9f\xdd\x22=\x8f\xd3\xf7\x14\x83\x11 \x8c\xeas\
-\x1f,\xceS\xb9o\xca~\x18 \xb4\xb3T\xd9#-\
-\xaeKD\x13$'\x89Q\x02`B\x99\xce\xa4q\x7f\
-\x935\xb3\x83\x9d\xbd\xe0^\xb9\xf2\xbf\xf5\x22\xd1E9\
-.J\xa3\x06j\x89\x1e\xfbI-\x09:]NY\xe7\
-\xdaP\xd77\xf4\xf9y\xde\xee\x9c:\xc0\x00Y\xdf\xcf\
-\xcc\x0a\x80p\xc7J\xfd\x1b\xc2\xbc\xc59tcq\xe4\
-\x84\xde4\x1dpN\xfa\x05\xf2\x01,\x80\xb8\x10\x14f\
-a$\xf6\xe6D\xe1\x14\xc5\xcf9\x0a\xbbcp\xf8x\
-\xe5\xf7\xb2\x88\xe3\xc1\x91\xbc\x876e\xf4\xd8\xcbg\xbc\
-\xc8\xc9B\xa0Z!\x5cKS\x99\xdb~P0g\x8c\
-\xf4\x0a\xe3\xa2^f!\x1b\x1d\x01Nl\xc68\x09\xbe\
-l\x81\xcc\xff\xd6'\xfd\xb4v\xbe\x0b1\x06\x94\xcc\xe7\
-\xa7\xf5\xf7\xd4\xd65z\x1cZ\x03v}\xef\x03(E\
-P\x13\xe4\xf4\x1a\x10.\xaeV\xb8\x06\xe6s\xb6D\x03\
-\xe7<\x9a\xd6\x8e^S\x1b6\xda\x11\x00\x9f\xc5\xe7\xeb\
-Bdwc\x11\xf78\x0aq\xc4\xbd\xe3\xf5\x91\xd1\xba\
-9\xffk\xcf\xff\xde\xff\xee\xdf\xf87\xfe\x87\x9f\x7f\xec\
-\x9d\xfe\xd3l\x80\xfb\xefW\xef\x5c\x058\xde\xbaD\x8f\
-\x8fO\x11[\xb08r\xa1x\xcf\x19\xe1W\xa9\xda\x1d\
-;(Z\x065.\xb2\xd4\x00\x0c\xdb\xdd\xb0b\x8d\xbd\
-}i\xac\x04\x99\x10\xe6p\xdb\xc7\xcb\xda\xe4\xa3\xeeS\
-\x09\xbdxZ\xa2\xb6\xc0\xbd\x95\x01\xb0x\xe6fo1\
-\xc0;\x8e\xfb\xab\xfc\xd0\xdeR\x18X;\xf7&\xd7\x95\
-c_\xa6Uu\xdc\xf7Dd\xa9\xa2h\xdf\x1e\xd4\x0e\
-\x04\xcb\x112\xd5\xd7m\x16/\x8bW\xf1\xa1X\xcaK\
-d0\xc6H:\xab\xa53\xc5\xae\x03\xc1\x12>\xe1\x8c\
-\x05kRzQ\x8dy\x0f\x9a9sSN;3\x12\
-\xac!Mj\x1c|\x14\x8e\xf0\xefO\xb5\xa1\x16\xb9'\
-\x1cs\xa8{\xa7\x825\xe5J\xefx&\xa3?j\xbf\
-N%7'5\xaf\x8f\x13M\x940k\xbaP\xc5M\
-\xe1M\xdc\xef\x0e5\xfe\xcb\xc6\x80\x8f\xef\xbf>p;\
-\xb8#o:$\x00\xc8N\xd6$\xe2\xe4\xf3\xe2\xbd\xd5\
-EX\xb1\xefyN \xd6\xe05\x11\xc8\xf3A\xf7\xaa\
-\xd8kk\x12.\xb1;\xe5.\xdb\xcc\x0e\xb5U:L\
-N\xedq\x9f\xb7\xc8\x9d\xa9\x0e\xe6\x5c\x1a\xce\xa2)\x92\
-\x08w{\xcep\x9ek\xa8\xb3\x14\x1c\x99\xc5\xcd \x18\
-\xd2\xd9Q\xf0|]\x94\xb2\xd5\xb0\x04\xc7\xee#g\xfc\
-\xe1/\x9e\xa9\xa8\x16f\x99\x9e\xee\x22`\x0a\xc7\xad\xde\
-Q\xdc\xc3\xac\xee\x82\x87&\x10Y;\xf9G.x{\
-$\x9c\xba\x1c\xb7\x85]$9\xe0~j.\x82\xe7\xf4\
-\xc5\xc8T|?\x12\x0c\x80O\xcf+\xe3]\x8d\x85\xb3\
-\x1do\xc7\x89\xe7+\xc1O\x9bV\x07#\x17\xe0\xbaF\
-\x11\x0c\x0b\xf6\x83 \x93\xafo;`\xd9\x99m\x0b\xa3\
-\xae)\xda\xe4A\xb5\x1f\x8a\x97\x15\xbd\xd0{\xae\x83n\
-\x07s\xdd\x19\x80\xc3\xe2\x85\x99\xf2\xdcq\xf3\xb9\xa4\xbe\
-\xc5J\xa47mL\x9e\x07\xf5\x18+C\xc5\xecqr\
-\x94Yu\xb9ZY\xb7hu\x14\xb8\xa9\xca\x13\xad\xef\
-gQG\xd9\x1aC\xb0\xce\xd4\xe0\x9d\xc7\x1a\xc2\x9c\xfc\
-\xbdl\x0b\xd3=u@\x1f\xb2\x9c=\x0e\x160\xd7+\
-\xd9\x0b_\xee\x09!\x18\x81\x988\xa2}\xdb9\x85\xbb\
-.\x11\x80~n\x15\xddY\x93\xc2\xe7k\x14\x8f\x9d\xcf\
-M\xca<\xc4\xd7\xe0T\xd4\xf5\x99\x0f\x010]1\x8a\
-\x9a\x98\x0ac\xb9\xa3\xa5\xbe\xc6\x0b/\xcdi\x81\xc7e\
-\xe3n7\xb76\xc7\xee\x8f\x94\xf4}\x00\xb5\xd2!2\
-)|\x9a`\xd6\xf9\xff\xa6\x1c\x82\xc8\xe9Hn\x050\
-\xc0\x9ei\x1d~\xde\x22\x0b\xd1\xc5\xc2\xb9\xf7\xf7\x10\x00\
-\x96\xd5Q\xcf4\x18)1\xe0\x12\x9c\xf4\x04\x1eo{\
-A\xf0\x0e\x975 \x17\x8a\xbe\x9b\xedS\xe4\xc6\xc0%\
-\x01\xa1\xd4\xad\x96\xd2a\x9cEN\xef\x94\xd7\xda9\x09\
-K\xa9\xcd\x15\xd1X)t\x00_\x1fy\x0ak\xeb(\
-.SU\xf6\x0bW\xa5\xd1\xd3qt\xa46\x85\xe2\x97\
-%`\xcf\x05\xbf\xf9|\xc0\x02\xf8\xe5\xa7gxg\xb8\
-\xb6\xd1\x8e\xdc\xc0\xe0u?\xa8!P\xe1\xf4\xe5\xce\xce\
-{\x13b\xfd\xfb\xb7\x9d\x11\xcf\x01x\x1c\x9c\xa0}\xbc\
-\xac\x5ca\x17\x89\xb6[\x9f\xce5N\xfd\x12\xb2\x0a\x05\
-g\xc8\xc4h`\x9a\xa01\x00L\xc7]\xc4\xc0\xb34\
-\xbc\xde\x0e(2\x03\xd6q\xcaU\x0a\xa7\x16?D\x9b\
-?\x12\xd7\x1a\xad\x8d\xb4]\x92$[\xe3\x9d\xb8F\x87\
-\x0f\x97\x88\xc5{M\xc9\x17Dg\xcb\xa3\xfd\xac\xfe\x94\
-;\xfd'M\x00\xfe\xc3\x7f\xff\xff\xb4\xfc\xd9\xf1\xf7\xff\
-\xe7/O\x97\xcd\x89dT\xfb4\xee\xcc\x7f\xaf\x03\x1a\
-YT\xa9H\x19\xa9\xfb\xf5\x91\x10c\x10\x8c\xc6\xe2\xf3\
-}\x9fjK\x80a\x07\x8f\xb3\xa05&a\xc5@\x84\
-\xe7\xfdLh\xcd\x88\xa2\x94\x15S\xc9\xdd\xb3\xb1\xc3\xe6\
-\xc4\x07m\xa86\xd1Y\x0d\x8e\xae\x05B\xf7\x04ys\
-G\xd7\x98k\xc7\x1a#w\xdf\x228A\x80\x14B\x86\
-\x02:\x060\xc5\xceq\xd0\x91\x8bF\xc2\xdcG1\x94\
-\x88\x1e\xf8\xe1\xd9\xdd\xa2\xc7\xfdH\x02<\xb0r\x0d?\
-\xa0buE\xaa\x02\xc0\x1a\x8db8\xf5\xc5h\x0a1\
-\xc0F\xbd3d\xc4\x18\xc3=\xb4\xc6\xcc!\x18\xf4N\
-\x91d\xe9\xefQ\xb5\xc4\xb2\x9a\xf7\xf4*\xa5^u4\
-\x98\xceI\x86w\x96q\x99*(\x8eD\x81b\xf0\x16\
-k\x08h\x9daL\xac\xe6y\x99\x7f~;pV\x22\
-R\xd1\x81\xd29\x92,\xc2\x09\xe7\xd2\xe5\xf3u\x1a1\
-\xf3\xd2\x88\xfe\x9d\xb8\x08\x88\xe7`\x8d\xc2\x8b\x80\xc7Y\
-\xe5e\x15\xe9Q\xff_\xb0<\x5c\x83\xe5d\xe8L\x19\
-\xd7\xcd\xd3r\x04NZ\x06\xc6\xb8\x14\x12\x0f\x8f\xd4\xa4\
-\x8e\xe7d\xe6\xcc\x15[\x8c\xf0^A;\x82\xf5,\x9a\
-b\x8d5\xca\x88\xb5\xe5\xba\xc6\xa8c\xe2\xbe\xb6\xd56\
-\x11\xd3cj\x03\x03\xa4D\x05\xef\xf5\x12I\x08t\xa3\
-\x105Bs\xb2\xd8\xaa\x8d\xee\x8a\xe8\xac^|\xab\xf4\
-4\xbaI\xb2b\xa5\x8d\x9e\xb5\xf1NXY\x1c\x19\xde\
-3 !T\xb8\xa7\xac\xa8^ur\xab\x92\xe9\xce\xcc\
-\xdf\xf9\xcf~\xfd\x86\x18=\xd5\xd6\xdd\xa8\xf33\xb4\x7f\
-\x0d\x84\xa8\x83\xd6\x0e\x1e\x8f\xc4N\x8c\xf0\x1b~\xe7\x0d\
-\xd4\xbbP\x94\x86\xf9\xee\x18h%\xe4\x19\xb44,\xa4\
-<\xe4\xd9)\x9dG\x9d /B\xc1*R*\xd8V\
-*\xe8\xbb\x94\xe4\xb9\xd4I\xea\xdb\x22G\xd3Y@\x1b\
-\xabsed\xba\x8f\xf3\xa2\x81\x93\x17+\x1fu\xed\xc3\
-u\xc1\xcf\xb1v\xd2\xf0.\x22\xe5\x8d\x7f\x169\x5cJ\
-\xe9x\xbd\x1f\xcc\xb4\xb7\x16)U\xac\xab'\x98'+\
-\xcdT\x7f\x971\x0c\x18\xca\xa5c\xf1\xcc\x8c(\xa5\x0b\
-:\x14\x15\xe4\xc4u\x12\xd1\xe2*\xc8\x0dEey\xa4\
-Fz\xc7\xbd\xb5\xa3E\xd2Xj\x97\x92\x22\x8a{\xe3\
-\xc5\xfe\xe1\xba\xc1\x19\x82i\x98U\xc0\xb8\xdb\x8e\x8et\
-\x92\x86\xd7;\xbf\xa3U\xd8i\xe2\xcc)\x9e\xa3\x00\x96\
-'\xf1u\x8b\xa8\xa5M\xe4vk\x8c\xe9\x86,\x8cM\
-\xf3\xc4\xd2\x06\xda\xdbc\xcf\x05g\xe1\xe8?\x0b\xe9\x5c\
-:\xdf\x81\x06\xbd\x1fC\xdc\xe6\xdf\xf3)Ft3s\
-`\xc9\xf9\xe8\xdd0\xaeV\x91\xdah\x06\xb0T\xdb_\
-7\x8f\xc7Q)\x943\xa4\xbe>m\x91\xb4V\xdd$\
-\xb5\x0dN\x04\xcf\xf6\xae\x7f\xf7,\x05\xe79&2\xd4\
-P=_\xc3\x9cP\x18c\xf8=I\xcc:\xa6\x10\xad\
-7\x5cWN\x91\xf7#M\xc6\xcc\x08\xe3\xfa\xfav\xb0\
-I\xfc\x01\x0b\x80\xfa'j\xae\xb2\xb4!>0Hn\
-\xacc`\x0c\x8c\xa3\xe3\xc5\x1b\x83\x8a\xf7s$\x97\x8a\
-\x10\xa8\x9b\x18\xfc\x07g\x1c\xbe\xde\x0f\xad\x0f\xa9\xa5\x1b\
-\x85\xab\xd7T\xb0\x81\xefz\x03\x9f\xb5\xd5{\xdf\x0fEd\
-\xb33\xeb\x1d8J\xc6\x9e3\xd2Y\xe1\x15c\xccn\
-\xa0N\x81\xda\x7f\xf2\xe7\xdf\xe3mO\xf8\xf4\xb4\xe1e\
-[`\xe4/~\xb7N\xbdO\x85\x06\x22\xb76\xa3\x22\
-\xa1bY\xc8Zp\x96\xfa\x91\xdc:Z\xafs_N\
-l\xa9\x9dJ\x7fg\xc9\xac8\x12\xa1GG\xce(\xb5\
-LQ\xda\xa9\xccy\xae&\x98\xf1\xbe-\x8e\xd3\x89\x95\
-\xa2\xc3\xae\x8c\x8a\xe8\x1c\xf6T\xf1\xf5\x96fj\x1a\x00\
-b\x89;s\x0d\xf6\xb3\xa2\xc9\x16{\x9e|V>\x5c\
-6r8Rf.\x06F\x8a'\xa7v}X\x12\xb4\
-fh\xad\xe1\xf5\x91q\x9eM\x97G\x9c\xab\x08\xeb,\
-\xae\xd1\x0b\x11\xce\xf5f\xc9\x14\xb9zGa\x18\xa7\x04\
-\xfc\xf7\xbf\xdc\x0f\xbe\x87{Bo\xd4\x81\xe4:$\xd0\
-\xfc\x99\x9c\x84\x98\x97\x95\xea\xee\xfbI\x04\xb3\xf7,|\
-\x8c\xe7EF\xfd\x13\xc7\xfe\xb5\xf3\xbf=\x92\x04nZ\
-\x01x\xe7QZ\x17\x01Q\x05a\x08x\x12\x18\x88d\
-M\x87\xdaY\xf8<\x8e\x8c\xfb\x99\xe1\x8cC\xc9\x05\xa7\
-\xce\xd13\x15\xbc\xed\x99\x82:\xf1-\x0c8\xb6/\xad\
-#\xb7\xcc?\xa7V\xc5\xe4\xa9\xf7:N~f}bk\x18M8\xd6\
-\x81\xb0\x16%U\xa8gB*\xc0\xebu\xc2\x16+\x9c\
-\xb0\xbeGJ\x04\x995\x06O9\xb1$\x8c\xde\x81\xd7\
-\x97@Tz\xa9\xf8|\xe7t?\x14\xae\x19\xadm0\
-(\xb0\x96\xfa\xbb\xdc,Zz\xfe \x11\xe0\x0fC\x01\
-\x07k\x825X\xa6\x19\x97i\xe2!`\xec\xc8w\x9f\
-\x83C`\xab\xcc\x07b\x99a\x8c\xc1\xdb\xfd@\xab\xdc\
-\x91u\x81V)\xc0s?\x11\x82\xc3\x1f}w\x1d\xc9\
-kg\xe4\x07\xfa\xe9\xc3Ju\xfe\x91\x06:\x96\xeb\x81\
-\xc6\xc0\x16E\xe1^\xa6I\x88`\xda\xed:\xc1m\xb2\
-\x86,\xed\xa4\xc0\x0a0\x8a;\x95\x0ao<#\x1aK\
-\x93\xfd\xc3\x03\xaa>\xd9\xf93\x0c\xa6\xb6\x86\xfd\x88\xaa\
-\xd4)\xe4\xe8\x94\xa7\xf3\xcc\xf8\xdd\xe7\x1d\xff\xe9\xef\xff\
-\x80\xb7\xe7\x01c\xea\xf8\x12\xa9\xfa\xa5\xcd\xaf'\xb6\xd5\
-V\xb1\x9d\x04\xad\xc001*\x04\x87\xc7\x11\x05D*\
-\xd8\xf6\x84\xe0\xa8\x85x\xee\x11\xad\x01k\x98I\xf1r\
-\x8eD/\x8d!\xb7\x94\xf1z\x99\xb4\x937\x83\x18U\
-E\xd43\x96v\xaf\x8e(\x9d'\x82Y.\xeb\x84\xdb\
-\xcaU\x0d\x0c$\xaa\x03.\xf2\xb8/!\x8c\x02\xae\x1f\
-\xa8Th\xb3\xeb:O\x1d\xd2\x86\x85M<\x19\xe9\xdc\
-*\xb3\xcc\x8f\xb3*\xd4\xc7\xe1\xb2\x04\xe9\x0a\xd8\xd1Q\
-\xec\xc7\x8cz\xef\x0d\xe6\x10\xf0\xdc3\x82\xd7\xc8{X\
-#\x81='e\x05\x98\xb1\x13m\xc2\xfe\x9e\xb9\xe1\xfe\
-\x88\x88\xe2\x0d\xc4\x5c\xc5\xf6\x16\x0c\xc9Y\xe5\xccS1\
-~(-\xb04v8\xc6\xd0\x1bO\x05o\x81\xb3\x84\
--\xf5\x9fqR<\xecq\x92\xf3\xff7\xbf\xfe\x8c\xbf\
-\xfd\xf5\x17\x8d\xe3O\x18G\x0bQN\x05\xa9\
-pT\xd8\x83B\x1e\xcf\x83dKo\xe8\xdcp<\xac\
-\x9cuZ/\xb0\xcb\xbe\xae\x13Bp\xb8(\x83\xbe\x19\
-\xe0\xf1d\xf1\xdbd\x81\x9c&\xfa\xdd;\x09\xef\x8ce\
-\xb04\xbc:\xf9\xfd<)\x843\x22`\x02J=K\
-\x14{\xf6\xc0\xab\xe0\x11\x95cP\x1a\x8b\xe9#s\x04\
-\xef\xb4\xb3\x8f9\xc1Y\xae\x06\x9e;i\x84<\xc4\xf8\
-~A{\xf7\xda*\x11\xbbz\x9e\x8bV\x84\xfd\x9d\xfc\
-\xab\xff\xedo\xf0W\xff\xe9\xef\xf1z\xb9\xe0\xf5:\xd1\
-\x9e\x97\xdf\xfd\xcfV\xb1\xbf\x97\x95{\xf9}\xcf\xb8o\
-\x11\xeb\xea\xb18\x8f\x10\xba*\xdb\xa2\xe6\x8c3r<\
-oe\x0f\xdd\x8eH\xb1\x99g\xc7\x9a+\x8bng,\
-L\xa3\x10\xb8J\xa4{\xbd\x06|\xba.\x0a\x0b\xa3\x0b\
-g\xeaHn\xad7\x8d3Xf\xa3<\x0b(\xcc\x8a\
-\xc7&\xd7A\xb2\xa7\x89b\xda\x8b\x0f\x02\x9c\xb8\x03/\
-\x8d\xab@kX\xd8\xd0B\xec\xa4\xee\xae\xbaT+\x9e\
-G\x81w\x0e\xdf\x7fy\xe0\xfe\xf6\xa0\xbei\xf2Js\
-\x94\xf6DE\xe3\x9e8\x05\xf3\x86\xbc\x86\xe7\xc1\xa6\xe1\
-<\x0b\xbcl\xd5g\xe4\xbbr\x7f\x9c\x80\xa9\xc8\x09\x00\
-*n\x970~F\xa0I\xa3\xc3\xbf?\xe6\x8ci\x0a\
-J$$\x93\x83\xf6\xbdB\xd1\xa8\xe9\xe9\xab
C`\x10\x85{\xeb\xcc\xcf\xa0\xaaK\xc9\xb5\xe8E\
-\xe7\xe8\xdbZ\x8ai\x8e3Q\x0c\xa7Q\xf2\x11\xc9x\
-\xef\x14\xb0\xeeJ\xb0zYb.L\xc9\xaa$\xa6\xb5\
-F6B\xca\xdc\xb5\xc5\x5c\x05\xf6\xa0\x02\xbc\xb4\xfe\x7f\
-\x17X\xd3F\xecg\x17\xa2YQ\x17\xfb\xff\xbe\x1dQ\
-\x17\x0a+\xfc-\xe6\xe1\xc0\x98u\xe8\x96,\x90\x90\xb5\
-\xa4D\x1a\xd2\xe1\xb2\xfc\xf3\xce\x19\x81\x8b\xb8_t\x96\
-Jn\x82o\x02Z1C\xa0\xca\x144\x87\xcb\xe2q\
-]\x03\xe6\xd9\xe3y\x9cx\xec\x11g\xaa\x98g\xda\xe6\
-\xfe\xe4\x17\xaf\xf8\xf3_\xbc\x8c\xec\x82*\xdc\xf1\xa1\xc2\
-\xc1\x1a\x8a=c,$\xfc\x01\xb2\x819\x5c\x17&\xa5\
-\xb5J\xba[.\xf4P9K\xcb%,'EMV\
-\xb0\xed`\xb2\xa6\x93\xe5\xac\xa78^W\x07'\xddM\
-.\x8dX\xd4B\x8bf\x8f\x836\x8e4\xb3\x0e\xa9J\
-9c;N\xc4\x9cq*\xfc\xe5\xbeE\x0a2S\x22\
-N:p\xd2R%>\x02\xe8\x99?\xce2:W(\
-\xc6\x15\xc0\xf0\xd1\xd7&\x80\x93u\xf0\xae\x89,X\x01\
-#\xe1\xaf\xe7\xe4b\x0a\xc0\xff\xed\xbf\xfbo\xf0\x7f\xff\
-\xef\xff/\x88\x95\x9dW<\x95\x8e\x97\x15u\xeb\x09\xfd\
-:\xce\x82_\xfe\x94ik\xe7\xd9Y\x09Y\xc1(\xa4\
-\xf7\xadS\xc0m\x9e\xf8<\x05\xaec\xceTq\xbd\x08\
-Z\xa5\x8b\x7f\x92Z\xba\x07\xc1pR\xc9\xee\xb85\xe8\
-\x02v\xe3PO\x85\x93Mgh\x97\x04d\xf7\x8d\x5c\
-\xcfu\xa2 @>E+]\xeb\xc4\xc2\xd4j\x82\xb0\
-(\x82\x9aI\x9av\x9cA\xcf#\xabX\xa1\xed\x8db\
-f:\x0b\x8e\x93#\xde\xafo\x0f\xfc\xed\xdf\xfd\x16\x15\
-t\xc3\x04\xe7\xf1\xf6\xa4\xe7\xbb\xa1\x8d\xa9\xa1W\xa0M\
-,\x15h,2\xfe\xe1\xfb;3\x15T\x80\xa6\xdc$\
-@mCL8\x07\xaf\xe2\x87 \x9cy\xea\x85\x1f\xc1\
-29\xb1P\xe8P\xad\xde\xdc\xa5\xc4\x95V\xe7\x7f\xd0\
-I1\xa15\xc2r\x8e\x94\x04\xfc\x22\x94,%\xd2\x06\
-\xb7\x18\xf1\xcb\x9f\xde\xf0r\x9d\x98\xe0W*\xae\xf3\x8c\
-\xd9\x07X\xebp\xc6\x8a\xff\xf9\xdf\xfc{\xfc\x87\xff\xf0\
-W\xb8o'\xa6\xc9av\x81\xe4>\x89Y\xabbu\
-\x01\x86\x9cu\x18T.\xb4\x04\xc6\xcc\xef\xfaP\xcc\xb3\
-\xd1%\xdf\x1a\xf5)\x06t\xa9<\x9fL\x9a\xed\xf9\x0d\
-\xce\x11\xf6c\x8c\xc1u\xf5zf\x1d*X \x05\xe7\
-\xf1\xe1\xbape\xacTS\xef,\xa2>_Z\x99\x81\
-g\x8c\x98g\x16\xef\xce\xd2\x09\xb1E\x06\xfe\x94F\xe0\
-[\xce\x0d\xcfHV\xc6vP\xcff\x1d\x9b\xa6\x9c\x89\
-\xfev\xd6\xc1\xc1\xe2\xb22('\xc6*>@\x16\xdf\
-\xc4\xe02O#\xc5\xb6\xb6\x86\x82Z\xfe\xd2\xff\x7f\x7f\
-<\x10\xd0\x7f\xb8\xffY\xda\xcbV\xd7\x97\xd5]\x17r\
-.c\xaaH:\xb0ZuH\xb5\xdb\xdf\x1c\xfe\xfa\xef\
-\xbe\xc7\xc7\x97\x05\xbf\xf8\xeeU\x95\xb1\xc6\x9f\x8e\x816\
-@\xc3?|\x7f\xc7\xb2|\xa2e\xc9\x18\x5c\x16\x8f/\
-\x8f\x13K\xa0\xf7\xa5\xd4\x86,\x16s\x1f\xb59}\x11\
-\x00m\x82\xd6\xb20(\x0a\x061\xc6\xa0\xf6\xb1\xbd\xf3\
-8#\x1f\xbee\xe1\xc5\xdf\xf4\xa0[cX\x0d\x1a\xa3\
-\x84%\xf2\x01Ny\x94\xe7\xc0]\xf2\x148\xbe\x9fg\
-\x8f\xcbJ\xb4i\xb7\xba\xa4\x5c\xf1\x8c\x14n}\xb9\x1f\
-X\x97\x00k\xd8\xf5/3G\xb6g\xcaX\xa7iX\
-\xa4\xa6\x99\xe2\x9f\xa2\xc3)t\x81\x96\x12\xd5:\x925\
-%\x92\xd9\xc8G'kk\xf6D_V%n\xbdm\
-\xb4\x14\xad\xda\xb7\xa3\xf1\x9fg\xc1R\x05\xb3\xa0\xd5e\
-K\xec\xc2{J\x9aw\x1e\xd6Y\xec\x07\x95\xea\xa6\x19\
-<\x9eQ{H\x8b\xe73\xe2\xd2\x03h\x12i[g\
-\xca\xb0x\x07\xfc8O\xb1\x10wt\x18;ZN<\
-\x9c\xaan\xa3\xaa\x9a\xd4Dg\x19\xfd\xfc\xd8N\xcc3\
-q\xb5h\x06\x93DCY\xb0\xa1\xeb\xb2\xe2\xeb\xf3\x84\
-\xb5\x06\x8f##8\x8e\x95\x97)\xc0{\x8f`\xf5\xfd\
-\x0a\x11\x9bR\x86\x05!'\x00\x0bQ\xfb\xcd\x10\xa4\xb5\
-\x8a\x02\xc6\x17\x07\x11\xbf\x98\x05\xdfFd\xaaw\xdd~\
-\xc6g\xf1\x94\xdd5\xe7\x86}'X\x8a0\x10\x1e\xc0\
-\xd6\xf0\xf0\x9c&v\x00g.x\xbdp\x9cz\x96\x04\
-o'\xbc^&\x1c1\xc2\x99\xa0\x08R\x8d\x1a\x01\x82\
-h\xf0\x9eA~]x\xb9\x89R\xad\xe8`\x8bm\xcf\
-p\xaeb\x9d\xc28\x0c\xe7\x99\xfb\xda\xd6\x1aL%R\
-\xfa\xb2p\x15\x01MwR&\xd4\xe7&tnV2\
-\x5c\xabM\xccu\x8a\x05K\xae\xb0\xde\xe83\xa4\xaf\xdb\
-:\x8a\xda\x8e\x14\xf9s\x18\x8b\xe2Xp\x13(Td\
-\x83l\x08\x93\xc3\xf3\x8cd\xfd\xcb:\xba\x04\x8b#2\
-\xb7\xfc\xc3\xf5\xa2\xd5\x11\x11\xcd1S\xc4\x16O\x83f\
-\xf5\xce\x16\x12\xe5\xfe\xf4\x17\xaf\x88\xb9\x8d\x88ok\x1c\
-.\x0b\x99\xfb\x93\xb2\xd9\x0fEN\x97\xc21m.\x8d\
-\x932k\x00\xd3F\x08Ti\x15\x01\x0e\xdeX\x9c\xb5\
-h\x82SP\x9b\x835\x19\x97\xc5\xd1\xaa\xac\xcd{k\
-\x15O\xb9\x87\xba\xc2=x\x83\xed\x94F\xc3\xf2\x00\xde\
-\xf7\xaag\xc7JSB\xcf\xfb\xd2\xa8\xb1\xb0`GW\
-\xb4\x0a\x02\x18\x94\x15\x82%-\xd48L\x01\x08\xe0z\
-\xea\xdf\xfcO\xff\x0eo\xbf\xfb5\x96\x97W|\xfa\xf4\
-I\x85p\xc1\x22\xc7HJ\xef\x8d^\xcb\x95,\x03\x11\
-\x14Kk\xb8\xae\x13\xbe\xbe\x1d\xf8\xf9\xa7+\xa3c\x1b\
-U\xfc\xc7\x19\xc74&W\x0a[\xd7iR`\x14\x7f\
-\x9f\xee\x00\xa2\x1b\xc8\x0c\x8b[\xb8\x0688\x1c9)\
-\x8d\x93\xb6\xcf\xd6\x0cl\xa3\x10\x9a\x1e\x7f\x8fR\x12Q\
-\xc6\x8a\xfe\xbe,\x5c#\x184\x94F!\xabq\x0c\xa4\
-J\x15X\xd6\x09\x8f\xb7\x0do\xdf\x7fEk\x0d\xbf\xfa\
-\x87\xdf\xe3_\xfd\xb3?\xc7c\xdfq\x1et%x'\
-&\x87\xa7\xce\xec\xcc\xd4\x13\x18\xb0h\xe7\xea\x83\xac\x94\
-\xd6\x1a\xdc\xd5\xe1\xeb\xdb\x89098\x18N\x03@\xb1\
-\x22\x1c\x08\x0e\xb2@u,,\xe7\x89\xabU\xde7\x16\
-\xcd\xb2H\xb2\x96\x05a.\xf4\xdf\xf7\x02\x1a\xa0\x0d\xb6\
-\x17x\x0d,\xb8\x01\xb9\xb7j\x86q\x18\x0d*dG\
-\xaf\xad\xe12\x11\x94T+Q\xc6k\xf0\xf8p[\x91\
-2\x1d*\xc1sb\x83\x08\xf6\x88\x5c3b\xa1\
-]\xf1L\x15\xcf\x83\xf1\x97\x93v\xf2\xb5U\xe4\xd4a\
-<\x0ds \xc2s\x12\x9b\xbb\xab\xf1\xe8o\x0d\xe2\xd7\
-\x1b\xa5\x19rzQ\x1aw\xb5\xfb\x9e`G\xfe\xbc2\
-\x132w\xd89\xbf\x93\xbb\x9c}\xff\x0eri\x03d\
-\x03\xc1Z^/\x1c_\x9e\x99\x16E\xe7\x19;}\x1c\
-\xb2\xea\x89\x86\xb4my\xec\x8a\x9dux\xb9P\xb9o\
-\x8d\x11\x16\x96\x13\x9bir\xec^A\xa7J\xf0\xb4{\
-6\x81\xafz\xf6\x01'$\x01\x9b\x04\xa9\xcdpj\xb4\
-.\xda\xdb\xabSx\xbd\xf29\xe1\xa5Qq\x7f\x1e\xa8\
-\xad\x8d1\xfb~d\x12\xc3rC5\x8a\xde\x95\xbf\xde\
-{2'\xacS\x10\x8e\xdc\x01}\xdfKOx\x1a\x08\
-\xe3\xb7\xed )\xf3\x88R27\xbc,\x0b\x82'\x80\
-\xa9\xe8\xf7\xa1\xe0\x96\xe3v\x80\x09i,$\xfd\xf0\xef\
-\xefg\xa1K\xa0\xd0\xfd\xc3\xe9A\x93\xb3\x82\xe2\xcf\xa8\
-\xb6xR!s\xc42\x9c3W]>\xc6X\xfc\xe7\
-_\x7f\x8f\x7f\xf8\xfe\x81m\xcb#i\xedz\x09x\xbd\
-,\x149F\x8a\x1cS\xe2\xa4\xe4\xc8\x19Q\x8e\x06\xef\
-\xc8\x8e\xaf\xe2H8gpU\xaa\xde\xe4\xfdp\x05\xd0\
-\x96\xe6\xf1\xf6<)\xf0\x1bho\xe6T8g\x15\xc9\
-\x5c\xc9p\xc8i\x88\xd9\xbc\xc0`N\xbf\x87\x11\x0b\xa4\
-\x0b\x12\x93.\x82\xcb\x14\xb0\x0b>5O\x1e\xb1\xd2e\
-\xb3\x84\xc0\x8b\xfb`@PLMvd\xae\xec\x82e\
-,\xb9\xeb\x05Wa\xd8Z\xae|\x9e\xba\x88\xf7\xcb=\
-b\x9d\x89\xa5\xdecebby\x1f\xcb;]z\xbc\
-\xc4\xb8^\xf8\xf6/oyy=\xcf\x88\xb7\xed\xe0T\
-\xccY\xbc^\x08\x1a;3\xc5\xae\xec\xacyJG\xd9\
-\xfe\x1a\x0cb\xe2dp\xf2AH\xdc,\xd2\x225\x1a\
-\xd6r\xea\x953\xd73E\xaax4\x0a\x8a\xb9\xae\x05\
-\x8e\xcc&\xc9\x00\x88\x95\x97\xdcq2\xa8\xeb\xe3\xcb\xa2\
-)W\x1e+\x92y\x0ap\xc6\xe0\xc3\xcb\x02g\x95\x7f\
-\xe2d\xcf,\x99\xefa\xe0\x22'\x13\x82\x82y\xd2\x1a\
-\xb0O\x7f\x12\xf7\xed\x0c\xf82B\xedB\xe8j~\xbe\
-\xd2\xdca\x9e<\x9f\xeb\xfd\xd0t\xc4\x0e\xfcsR\xf8\
-O*y\xd8!{:\xeae\x0e\x0c\x0c2\xb4qB\
-x\xe3X\xf28\xbf,w\xaf\xd4\xf8\xc8QRJ\x1b\
-\xdc\x8e\xb3T\x09\xa0\xad\xf4Ur\xbd\x05\xa3\x14S\x92\
-Y\x8f\x93\xc4\xc8\xe7~\xa6?\xd4\x97\xfdG+\x00\x9a\
-i\xd5\xb4V\xb2v'N*\xddV\xfa8\xc4h|\
-E\xd1G\xcc\xdd\xef?\xd1W\xad\xcb+\xd7<\x02V\
-\x8e\x94q\xc4\x8a\x22\xe2\xd6!B_\xe9\x97X\xe4x\
-\xf92;\x18'o}j\x82t\x18e\x07\xc8y`\
-=B\xe0\xcb\xf4\xdc#\xe6\xe0D\xf3\xd2n\xd2\x13\xa2\
-Q\xd1\xc6\xc3\xeb\x9d\xc5\x9b\x82gz\x10\x0b@\xb5\xba\
-1\x169\x17\x1cC=\xcf\x17r\xf2B\xe8j\x8fE\
-\xff\xba\xc1\x9e\x0abN\xa3\xfak(\x22^qg\xef\
-\x0c\xdd\x0b\x93\x000\xd63m\xec2\xbf\x0b^\xba\xba\
-\x9e\x01\x10@\xeca\x8fz\x9fS-\x88\x91\xe3\xb9\x8e\
-c\xa6@\x8e'v\x12\xb6\xd8K\xe05\xcf~X\x93\
-\x9c\x8a\xb3\x10$\xe6Q%o\xc1*xOe\xeci\
-c\xa2\x17\x99\x05\x87\xd1a\xceD\xbe9t\x11W\xc6\
-\xe7\xaf\xbb\xa6\x05\x80\x0f\xea\x0a\x04T:5\xae\xf7\x8e\
-)Z\xad\xf2\x85,\x95\xd9\xf6\xcbD\x9f\xb21\xf2\x9b\
-K\xe9\xbc\x8a\x9bm\x0dijFAE\x14K\xf6\xc3\
-7\xe8\xf72c\xbc\x98\x1b\xb5\x07\xcbL[\x5c\x17v\
-\xf6\x17\xbe\x94\x82\xcb\x14\xf0r]\xb0\xedI\xb4.\xaa\
-\xec\x81\x86\x8b\xfe\xdcT\xb2\xc4v\x0d\xa5\x18\x18C\xfc\
-m\xcf\xe7.\xa5\x07UQ\x18\xe7T\xfc\x1a8\xfd\xfe\
-\x0c\xc3Y\x02\xed\x9d%74M\x87\x9eG\x94\xf0H\
-J\xe3\xda\x86&\xa5?\x93\x10]m\x99=r\xce\xb4\
-`\xc6\x8a,\x96\x05]\x03\x845\x95V\xf4\x0e\xa4A\
-/\x0b\x9e\xc5L\xd5\xf3\x9a\xb43>\x8e2Dp\xc6\
-\xb0\xfbdF\xbc\xc7\xebm\x01*/\x8aZY\x84\xf7\
-\x1dq\x87o\x05\x15\xfe1\xf2\x90\xf5\xce+?B\xd6\
-@\xad\xfcv9\x09rn\x83]\xd1\x03\xa7\x00F\xc7\
-\xf6K\xf4\xf3}\xc7\xb6\xc519\xea\x93\x83\xe0=J\
-\xe5sy\x942\x0e{:\x1b\xde3\x0dR\xce\xef\x90\
-\x19\xc3Q\xb0w\xe2\xe0k\xd5\x933\xedWQk\xbe\
-\xe3\xe0\xc5\xd3\x1b\x83\xc9\x87ao\x8c\x91T\xbdu\x0a\
-\xc8\x05hZ\x81\xa5L\x9e\xbe\xb1\xef\x99\x031\xd1\x82\
-\xd7\xed`\x937\xa3\xe0\xf6\xb6SO\x0b^Vu\x9c\
-\xb9\x92ZY\x9b\x92\xe0\xda\xb8\xf4;\xc1\xb3\xc9\x1aX\
-jC\xcdu\x04\xf5t\x8c\xf8\xe4Y<\xd7L\xdeA\
-\x8c\x15\xcf\xb3\xbf\x7f\x9cx\xce\x93W43\x8bzZ\
-M\xd9\xc1~\xabyh\x8d)\x92\x00/\xf7]E\xca\
-~\xea\xf2\xf5V\xff\x1c\xb3)h\x0f.83\xc5\xb1\
-A\xe7/\x00<\xb7Sn \x8f\x97\xdb\xac\xb5\x04G\
-\xf99sbr\x7f$\xd4\xdcFr\xdeua\xa7\x1b\
-\x0b!>\xcf=\x0a\x14\xc4\x091\x0b\x0f\xea6b\xec\
-Bsi\x09\xac!\xf3\xa3\x14\xdc\xb78\xac\x9fg\xac\
-\x9a\xd6\x16\x94Z$\x92fAp\xa4\x8ae\x9a\x10c\
-\xc5}\xcb\x88\x89\x05\xab1\x14,\xf7\xf37\x8b<\x9a\
-\x0a/\xe3e\xf6\xef\xa8\xe9\x89 \xae\x94XdR\xd0\
-ie\xd9\xe3\x9a\x07\x9d\xef\xdf\xa8E\xeaB\xbf\xa0\xa2\
-\xaf\x1b\x93\x1a*\xae3Q\xd8\x9cT\xf2?\x7f\xdb\x0e\
-XC\xcdW\xa9\x99\xb4\xceZ\x91r\xc2)\xb7\x92!\
-\xe9+5\xd3~\xbc\x15\xc0\x9f\x5c~\xd5f\x9fs\x8c\
-\xdc\x09O\x81t<\xee~\x9a@\x1c\x80\x83\xc5q6\
-U\xbc\x190\x0d\xc7\xd9\x1f \x8a)\x96\xd9\x8d\x8b\xa4\
-\x99\xaa]\xaf\xc1u\x0d\xf0\xcekDi\x11fV>\
-\x04\xde\xa4AI\x0a\xc1b\x9a\x82\xa0\x1fV\x81\x1d\x09\
-)ex\x03\x5c/\x93BX\x0a\xf6\xe3\xfd!\xe7\x1e\
-\xceh\x5cH\xafv\xbf\xe0 \xb8\xc9qf\xa0\x15\x86\
-\xe1xR\xfcr\xe5X\x16\xe8\x81(\xf4\xa3R\xcf\xca\
-Q\xe5\x87\xeb\xc2\xe0\x12\xd1\xab\x82\xeb\xfeRN\x19\xbe\
-n\x07\xce\x0e\x9e\xd1\xde\xb5\xb4\x86-\xa6\x81AM\xb9\
-\xc3sx\x81Y\xd3/\x88&b\x1es\x0a\x8e\x98\x94\
-\x16\xd5-c\x9c\x9a\x94\xd6\xf0xRM\xea\x9c\xc3\xb6\
-sJ\xb3,\xfe\x1b6\x00\x85_\x14\xffe|yc\
-\x11\x19\x9c\x95\xb6\xc2r\xf2`\xcc \xf5\x01@,\x14\
-\xe6\x5c&\x06\x12\xad\xf3\xfb\xeep\x9d\x03j\xadxn\
-ytJ\xde)\xa1M\x00\x95,\xbe\x81\xfff\xdc\xdb\
-\xfd\xe7\xcb\xc2I\xc2\x1a<\xf1\xb0\xc6`\x9a\x02\x96\xc5\
-\x22KH\x89\xd6\x14\xe2\xe19\x06d6\x13\xb5\x19\x0b\
-Ute\xf9\x00\x00\x80\x00IDAT}\xdd\xcf#\
-\xe2\x88E\xc8\x5c}W\x82\xe9L\x81S\x93\x983.\
-\x97\x19\xc19\x1c\x07\x95\xe1\xc62\xbb\xde\x18\x90\xd4X\
-\x0b\xbca\x9c\xaa1$M\xf2El\x12B\x01o\x8f\
-\x13\xf7=\x22\xe7\xac\x0cy&\xb3=\xf7\x84\x9ch\x0b\
-\xdb\x0f\x1eDG\xac\xf8\xc3\xd7\x8d\xf9\x11\x9e\xa2\xc6\x8e\
-6M\xb9h\xf2\xc5b\xe18\x0a\xde\x9e;\xde\x9e\x11\
-\xb1\xd4AN\xb3\x96l\xd2\xd2\x1a^.\x9c\x9c\x95\xac\
-\x10\x13\x80a'\xadJ\x0f\xc1\xeed\xdb\x13\xa0\xd0\xac\
-\x5c\x12\xd6\xa0\xf1|\xed\xbbE\x12\xe7rm\xd8N\x8e\
-Y\x1f\x07\x81H\xb3\xf7\x8c\x1dm\x5c\xa9p\x95\xe01\
-M\x16oOz\x9di\xf9\x12w\xa2p]\xd6\xc7\xc7\
-/\xb7I\x88\xef\x9e\xe4I\xec\xf2\x9e\xf8\xec:k\xf0\
-\xcf\xfe\xf4;\xfc\xd3?\xf9\xa9&\x88\x18\x94\xbdZ\xc4\
-\xd2\x90.#x\x0b\xe3T\x097\x08\xafLWO/\
-\x90\xf73\xe1\x8cu\x14|\xc6@\x9c\x0a%\x1c\x06\x0a\
-V\x83\xb7\xb8\xef\x09\xc7\xb0\xd6Q\xac5y\xb2\xf4\x8b\
-\x923C\xc0\xc8^\xdfc\xc4\x16\x13\xb6\x8dl\xf89\
-\x04\xd0\xc9\xa9\x00%\xcb\xdc\x89I`\x9d\xd6\xf8\x5cU\
-\x80)y |\xeb83\xe69 J\xc0\xd9T0\
-\xb4F\x8d\xcd\xb6'Mc,\x82\xf4\x1b\x1d\xadm\xc4\
-\x92\xf7Z\xebu!)\xd1\xc9\xb4>N\xc1\xb1\x0b/\
-\x05\xcero\x9esU\xaa\xa1\x13\x1c-K\xec\xe9\xe0\
--\xcfpN\xa8\xbc\xdee?\xa6\x029e\xfc\xee\xf3\
-\x86\xff\xf5\xbf|\xc6\x97\xe7\x89\x5c*\xd6\xc9\x91KP\
-\x1b\xbe\xde\x0f\x1cg\xc1y\x16\xac\x0bY\x0c)\x93|\
-Y\x1b'\x14\x97y\xc6\x14<\xae\x17ZW\xad\xec\xad\
-U\x98t\xafg\xad'\x93\x02 \x0cN\x9a\x8dZ\x1a\
-y\x09)\xa1\xe42tI\xa5\xd5\xc1\xdch\xa2\x04Z\
-G\xb1 \x7f76\xa9\xf3\x1c`D@\xfc\xfa\xdc\xf1\
-w\xbf\xff\x8a\xf4\x0d\x0c.8G\xcc\xbb3rf\x90\
-3r\xbbL\x5c\xd3D\x82\x9d\x82\xfew'\x97\x09\xc3\
-\x97x\x0f\x14\x15\xe6\xa5\xf2\x8c\x02\xea\x00\xa6\x95\xaa\x09\
-\xaf\x10\xc2^\xdfW\xcc\x15\xdf?\x0e\xec\xb1k$\xb4\
->\xb2\x9c\xfa\xf6\x86\xa0h\xb2bd\xaf\xb4\x9e\xf7\xd6\
-\xe2j\xfe'\xfb_\xffx+\x80\xff\xd7\xbf\xfd\xe79\
-5W\x97\xd9J4aQ[?L\xf8\xf78c\x05\
-\xd2\x81\x08r\xca\xb8\x97Ul?\x0a,(z\xe9\xdc\
-\xefu\xf6\xb2\x1f\xf1\xc3\xdfN\xb2\xbao\x12\x99\x9d)\
-I\x94\xd4\xefi\x8e\xbbbL\x1c\xd9\x07\x8e\x1aC\xe0\
-8\xb8W\xf3\xd68E\x82z\xa0\x19~\xd0\xd6\x0d\xbf\
-\xfcu\x09\xa3c\x9e\xa5\xe0<\xce\xa28\xce\x8aV\xcc\
-\xd8\xc31\xc4\x85c\xd9e\x0eDbZ\x07g*\xee\
-\xcf\x84\xcfo;\x15\xa0\x8d<\xee.\xd4;\xcf<\xe0\
-$\xcb\xe4\x86\x1f4\xe6\x82\xc5;\xcc\x12\x90\x8d\xfcp\
-\x09\xc1\x9c\xf5p\x0a\x0a\x82ixHK\x10\x9cC\x93\
-\xe2:\xd7,\xee\x01\xab\xc9\xd4\xe8\x85\xbe.\x13L\x03\
-V\x89\xb0\xce\xcc\x1d\xf2\x99\x18\xef\xca0\x8c\x84\x94\xa0\
-\xfd!ii\xd6\x1a\xe5!\x88\xc3n\xa0\x83\xd1k2\
-\xc1\xcb\xe9!\x08\x11\xc0n\xac\x17Eg*\xf8/\xbf\
-\xf9\x8c\xb7\xfd\xc4c;\xf1\xf5I\xe6\xf7s\x8b\x98\xbc\
-\x1f\x0f]\xd6\x81\xd8\xaaA\xb0\xdc\xcb\xf6uDn\x15\
-1\xf3%(\x99\x97|\xf7\xdav\xd1)DV\xcb\x95\
-H\xd8\x9c\xa9^\xbco\xa7\x94\xf2t\x85\x18A?,\
-\xde\xb1\xa6\xcb\xec\xf1\xd8)<\xea\xba\x82\x5c\x0aj1\
-\xe2\xe43\x1f\xc0~\x93\xe8\x06\xf4x\xe9\x19\x97%\x90\
-\x96\x07\xc2i\xbcF\xef\xd6\x937=\x05'a[\xc3\
-v\x16\xb4\xda\xc6A\xbf\xce\x01\xd7\x95\x5c\x85\xc7\xf3\x18\
-\xaa\xf5\xdb\xc21\xec\xec\xbd\xc6\x99]\x8dl5\x85\xa9\
-\x12\x15B\xd1\xc8\x00L\xc5\xb2\x10\x9d\xfdx&\x1d(\
-\x9c\xac\xc5\xc8@\xad\xf3\xa4]\x8e\xc17\xc0\x8b\x10\xb8\
-\xf9^I\xfb\xf2\xfb\xaf\x1b\
-\xc3zz\xa44\xc0t;\xe8\xe7\xec\x08k\x00\x8f#\
-a\x9e\x03\x0be\xe1\xb8g\xef\xf1xD|\xbe\xef,\
-b4\xcaf\xe3\xd2p\xdf\x0f\xd4f4\xee\xe4\xfe\xf8\
-<\x99\xd9`L\x7fW-\x96\xc9bv\x16\xa5\xf6g\
-\xd1)<\xcb\x22\x04\x1e\xf0N\x04I\xa0\x0d\x1b\xa8\xd5\
-\xe7\x1d\x02\xd7ojT\x07\x1b \xa6\x8c\xcb\x12$X\
-\xa5h,\xa6J\xdc\xb6\xeby\x08up\xfby\xa1\x98\
-\xa1H\x8f\x89E\xe9\xc7\xeb\x82I\x93\xb8\xce>\xef\x87\
-y\xf0\xdc\xd9v\xc6D+\x05\xb7KP\xd6\x00\xd0\x0a\
-\x0bc'\xa0\xda\xbeg\x89\xc7\xecH^\xf4\x96\xbb\xfc\
-y\xe2\xef\x9e\x94\xb4i\x94\x1ba\x0d\xe4\x85\xe742\
-\xa7\xca\xa4J\x9d\x97\xb9\xb2Y[\xe7\x00\xeb\x1a\xbe\x7f\
-\xdb\x98\x81`9\xdaOE(\xf5\xd4Tl\x99\x01I\
-\xfa\xfb\xdf?\xb0G\xc2\xc6\x8e\x98p\x7f\x9e(\x8dE\
-\xedcgg\xee\x03Y'\xcb\xe2\xc9\xe9\xaf\x959(\
-\x8e\xca\xcc\xcb\xeaq\xe6\x84\x98h\xf1\xd9\xf6,\x81\xf6\
-{\xb0\x9b\xb5\x04\x7f\xad\x0b-\xcdG\xe4\x14\xf8,Y\
-g\xb3\x1f\xd3\x1c\xe6,\xd0E@'\x06?og\xcd\
-\x00\xa9\xf9\xc0\xa0\xac#qJ\x8b\xd6\x10\xcf\x88_\xff\
-\xe1\x81\xbf\xfb\xed\x1b^o\x17\xfc\xf4\xc3\x85\x13\x17p\
-\x8a\x14S&56\xf0\xfb0\xe0Z\xf189\x05}\
-\xc6\x88\xe7\x9e\x10\xbc\x8a0Yq\xf9\xbc\x0b\xcc\xa5\x82\
-z\xdb\x0a\x9a!\xf4\xae\xa77v\x81,\x0b'\xae6\
-\x8bV\x14\x04\x12\xf1\xbbb\xae\x02\x9dSF\xd30o\
-\xad\xe0?\xef\xe7r\xad\x15\xa5\xd9\xfa\xff\xfe\xfa\xa7?\
-\xc8\x06\xf8\x83\x0a\x80\x9f\xc4\xff\x5c[\xa9\xe9\xcc=K\
-\x9d\xe2\x0cv\xc3\x15\xcd\xf0\xff\xa7T\xf1\xd8\x22G\x8f\
-\xa1\xa7\xf0q,W[\xc5\x912\xf6\xb3\x8c\xb4\xafV\
-y!W]\xb4=Z\x94\xff\x0f\x88\xb1(\xcf\x9a{\
-\xb23e\xdc\xb7C)\x84\xac\xb0Y\x99q\x97s\xa4\
-\x8c\xe3\xc8\x12\xfc\x18\xb1\xa0\x99\xae\xb6\x8b6gM\xc3\
-\xdbv\x02\x1a=\x16\xa5\xb1\xcd\xb3\x1b1\x8cPx\xc4\
-y*\xd0B\x07\x9f7\x16\x8f\xf3\xc4?|\x7fG.\
-\x0d\x9f>,\xb8\xac\xdc3N\xce\xe18y\xc1\xef1\
-\x09h\xd1\xf7L\xdc\xab\xa5\x9cq\xbb\xcc8\x14-\xd9\
-\xff\xfb>\xb2\x9d'\x87\x5c\xc8+H\xa5\x0d\xae\xfd\x22\
-2\xdc\x91\xd2\x10\xa4\x01\xc0\xdb#\x0e\xbc\xef2\xb1\x00\
-\xeb\xbdMWJ\xb7\xc6\xd1c\x83\x92\x02\x8dA)U\
-`\x1b7F\xd1\xcc$\xa0Z\xb9\x8f\xd3z0\x911\
-\x9d\x97^a\x0dG\x8aAj\xf8\xfb\x16a`\xf0g\
-\xbf\xf8\x88`-R&Dc\x99\x98\xe8x\xa4\x8c\xf3\
-\x1b\x98\xc9\x1c\x84\x0f\xcdI\x18\xd5:\x0e\x9f\x9e\xa1\x0d\
-pj\x93\xa4\xec\x8d\x85\xa3\xdf\xfb\x1ea-\xb0NL\
-\xacc7\xd0S\x1aY\xe0\xa4\xdc\xf0\xdc\xcb\x88\x1f\xbe\
--\xf4\xc7\xefG\xc2\xeb5\xe0\xd4\xaer\x99\x02&\x1f\
-\xe8:\xb1tBt_xLy8<\xb6\x9d\xe2\xb5\
-\xfd`\x97y\xa6\x8ciV2\x19\x1a\xa1D\xfa\xa1\xbb\
-&!'\x16\x12\x17\xb1\xc3\xe7\xc9\x8f\xc2\xc997b\
-c\xe9\x9e\x91>F\x828\x86&q\xdd4\x09M\xbd\
-\x04r&\x96\xa0\x02U\xd1\xa9\x00p\xdf\x938\xed\x0e\
-V\xff\xd9e\x0d\x9ar\xbd\xef\xbc\xcfL\xfa!\x9d1\
-\x14\x18\x85\xc0K5\x04\x83=\x9e\xf0\x12\xf7\x1dg\xc1\
-\xbf\xffO\xbfG\x8a\x15\xd3\xe4I\xd2\xd4\xd8\xfb\xf5\xc6\
-\x8c\x8b\xd2\xa8\x1d\xd8\x0eF\xdc\x02\xdc\xa3\xc6.*\x14\
-\xe0\x8bE\x9c\xc5v\x14\x05\x19Y\xad\xf0\xbc\xf6\xa1\x1d\
-\xad\xca\xcbt\x11\x0f\xdf\x18v\xbe%7X\x08[[\
-4\xc2\xf7\x1e\xad~Cz\x02\x86\x96\xe6HL\xd0\x0b\
-\xb2\x22{\x915\x97\x85\x9d\xfb\x1c<\xc7\xca3w\xbe\
-\x87\x8a\xa5\xa5w\xe7\x85\xc2?@I\x8d\x9e\xf6B\x03\
-\x81\xaa4\x01\xcb\xd2\xadPxIN{JJ\xcf\x93\
-\xde#(\xddq;X\x18\xc5L^}_\xa3\x18\xed\
-\xb8\xe7\xc9\xbd\x0b\x15\xbd\xff\xc6>\x07\xb9|\xb2\x8az\
-\xab\xe2[k\x1eO\xfe~\xa9
\xccN\xc2PF'\x81\x82Fn\xc5\
-\x91)<]<\xf3'^\xf6sb\xa3?\xbe\x1c8\
-s\xc3\xed8u\xd2Q\xd2\xa4\xb3\x88\x9a+FY\xd4\
-\x06d\x87\x9b?\xf5 O\x97(\xc0\x15_\x9f\xb3f\
-\xfa\xd3W%\xcc\xedgQ\x10V\x9f,\x81\xda\x0d\x9e\
-\xae\x01\xd7KPJ\xdc#X\x89c\xa1\xc1\x98\xe7\x82\
-\x9c\x0b\x83\xb5\x06C\xc1\xc82\xd7\xfa\x03\x95|\xd5&\
-\xe4\x8cA\xe9\x15G\xe2X\xef\xc8\x99\x82X\xf0{~\
-\xf5\xf1\x80\xf7F\x01`]\x0b\x1e\xd0\x0a\x0b\xd5CY\
-\x0b\xd0kZ#G\x91\x8c\xce\x95\xee\xa0\x03GQ\x06\
-\xc2=\xe1\xd3\xf3\x89\xb30ep\xdb8\x9a\x09\xfa\x1e\
-\xe79\x9cT,\xb2\x8eR\x85\x19f\xbc\xef=%\xc6\
-x\x07\x8a\xeb\xbc\x18\x02\xceZ\xf4\xd6a\xc0{\xb8[\
-v\xab.\xab\x87\x85\xc1\xf3\x9e&_\xa0\x83\xeb\x18\x80\
-9\xfa\x02\x0cv\x8dT6\xbdwF\xae\x9c\xda;\x09\
-\x91\x1d\xb2\x05\xf2\xeb\x9a\x8a\xe3\xd2;\xac\xeb8j\xc3\
-\xcb\xc9\x08\xee\xcb\xe2$l\xa5\x0b\xeb8*\xd9\x07j\
-\xa5\xb3U\x1d\xa6~\xc2[\xcb\xc3K\xe7I|[\xe4\
-.Qq\xfan[\xb1\x8a\x81q?2`\x0d)\x9f\
-\x0a\xc6\xd9\xcf\x8a\xab4;g-\xb8.\x81I\x9a\x18\
-^x\xb6\xe4K\xa9\xb3;\x195\x822\x03l\xd5\xa9\
-\xdd\xda\xd6@1\xa9\xa1\xc3\xc0\x19\x8e=G\xb5\xcc\xc3\
-b#\xb7\x221\xa5t]\x19\xb64\xd20\x87\xb0|\
-\xf1\x11\x7f\xf6\xf5\x0d\xb9\x15\xec'-\xe5O\x1b\xbb\x0b\
-t\x13h\x03\xb4\x06{\xcaH\xb5\xe1\xd3\xcb9Y\x0c\
-\xc1s\x9f\x80FyA\xcf\x1d@\xed\xd8\x12\x1d~\xf4\
-[\xbf\x81\x7f\xeb\xbf\xf4ClK\xa0v%:\xe9\x11\
-hOu\xe0x-\xfa\x07\x12\xbcK\xa4\xf8\xc5\xfb\x0d\
-Kt8r\xc1]cm`\x08\xd7\x13B\xf4\xd8\xcf\
-\x02gy\x08N\x023\x01\xc4\x88\xdf\x8f\xa2\x08w_\
-V\x1b\xd3\xaf\xbc\x00\xf8\x10\xbf\xcc\xad\x13\xe9k\xb9V\xac\x8b\x95\x95\x8a?\x1f\xc0\xbf\
-\x87\xa2&\x0aZG\xd7g\x88$\xe9mW6\x80\xe8\
-\x83\xd6\x18\xf1\xcbi\xad\xb4\xceLK\xabW\xab\xbcU\
-~8C\x07P\xa5)\xc8\xa5\xa8\xa3BOx\xae\xbc\
-\x17\xa0.\xca\x1a\x07\xe5\x90\xff\x94\xca\x03\xc4%Fv\
-9\x1c5\x12\xb7\xa3(zU\xf7\x8b3\x82i\xf5\xf9\
-\xda\xb7\xc5\xceq\xcat\x994\xc1\xcc\xb8\x0b\x22\xaaC\
-6Z\xdb^\xe2\xadVim\xfb\xed/\xaexw]\
-\xb1mt\xca\x8cMs\x0d\x011\xbaiK\x0b\xc1\xcd\
-1O)LH]\x16\xa7\xcf\xcd\xe0v\xcb\xdf\x98\xe9\
-\x9f\xb9\xb2\xe3tV|\xf9\xe9\xce\xd1\xa7\xa5\x06\x83\xe8\
-\xf5\xf6 \xd9u0f\xbb5\xf8\xe5\x8a\xdf\xfd\xb7\xff\
-ml\xd1\xcf\xa2z/M\x91\xe1NE&\x94\x0b\xf2\
-\xc8\xfdH\x1am\x8e5kO\x15/\xf74+\xba,\
-\x9e\xc9<\x88I\x87\xe1,pY\x16\x8d\xbc\xe8m\xef\
-\x9d\x9b\xbd\xe9@J\x856e=s<\xb8Y\xd25\
-e\xc1\x1d9\x0e\xc1\x9b\xc9\x16\xf0\xa2\xf5\xb1\x83\xc6M\
-\xd2z:\x85\xd0(2\xdc\x16\xc6\xe8\xde\x8f\x8a\x8aN\
-\x94pb\xd1a-\xdd8A\xd0\xb3\xa8\xe2\xa5V\xf2\
-\x0b\x82c\x97st?\x8f\x83\xe2\xbcC\xc9\xa1\xa67\
-\xac\x0b\x85\x96\xadu|z9`\xe1\xc4\xeeP\x92\xa2\
-\xf1\xe2\xb3\x18\xdcS\xc1\xcb\xfd\xd0\xb3M\x0b\xe3xO\
-\x17\xafN\xa44\x16\xec\xe2q\xf4\xf6\xd5\xf3\xce\x11\x11\
-\x8c9\xb4\xc5=\x84\xbc@+\xcd\xa4\x94QJ\xef\xc1\
-o\xd6\x99^\xde\x9b\xaf\x7f}\x1a\x80O\x9fn?]\
-}y\xae\x15.8\xa0W\x98\xc5\x91\x9c\xe4\xbc\x85u\
-\xd6\xd6\x82`\x83\xf7\xaduc-\xa6\x22\xfd\x94\xd8\xec\
-\xd3=\xc9V\xa4\xb4\xa7hq\xbdD\x94B\x1cd\xf4\
-\x8e\xf3t\xcd\xce\x8eT&|%UnH\x16\x06\xad\
-V\xc4\x10\x98\x99}6\x91\xfeX\xf9\x1f\xb9\xa2j\x1e\
-7\xe8d1P={H`\xc7Y2m2\x15R\
-\xaf\x0e\xb1\x93\xd4\xde\xe8\xeda\xe9S|\xa9\xd1)f\
-\xcc`[\xe7\xeb\xf6\xc2Lr\xeeo\xa6\x9at\xb4\xd0\
-\x96H\xddC.#`\xc6\xca\x0ai\x04\xc4i:)\
-\xe9F-\xa4\xd1\x0dP\xce\xb0_\x19-\xcc\xb9u8\
-\x89\xc2\xba\xdaf\x03sy\x8a\xa0\xd7z\xe7B\xa3\xc2\
-!e\x09\x0a{\x87\x0f\x16N\x0b\xda\xb2pa\xce\x8a\
-\xac=\x94\xc8\x15,\xfd\xac\xb4\xde\xf13\xec\xe0i+\
-\x95\xc6\xf0\x90\x11d\xa3\xca\xbc\x89\xba\x17\x05gY\x82\
-G\xb0~\xa6|Y\x89\x05\xefg\x92j\x163\x9f\x1e\
-Z\x04\x9d\xe3\xe2\xd6\x1a\x08\xec\xf1\x86v\xa9W\xca\xec\
-\xd1\x01\xa0\xb5\x91\xda\x88n\xfa\x0cZ\x09J\xfdjR\
-Qs\x01x\x9c$\x83\xa0M\x8bw\x08\xd1\xd2\xceT\
-x\xa2\xdd\xd6\x88>|\xe1\xad\xa0\xe9\x7fP|Z\xa7\
-\xaa\x18\xdd\xe8\xe4\xcd\x02!\xbe\xca.\x18\xa2 \xa7\xcf\
-k\x9c\x1ej\x03V\x81t\xd6\xa8qM\xb4\xfa:\xcc\
-\xbf\xc7\xc8\x12\xe5\xe5R\x18\xf7]P\xe7\x84\x9b\x99B\
-[\xac\x01Z\x9dP\x9e\xf1\xf5\xa3ca=\xe6\xfb6\
-T\xff\x00\xdf\x03\xef\xd8\xfaf\xa8\x92\xc3\x22\xad\x81\xb3\
-\xd4\x0e\x0c\xfc\xf2\xb0\x95\x0e\xb2\x1c\x17\xfc>\x95\xde\xad\
-\x13\xd2\xe2\xc4\xa7\xce\x99E\xd8\xe8\xf4\xb5\xdeg\x88\x96\
-Q!y\x9em\x16;\xec\x18\xb1\x83w(A\xd1\xe8\
-5\xadq$E\xb2em\xf5\x9c\xd3\xca\xc7\xc2\xc5\xbb\
-\xe1f\xe1\xcfd5&\xc9\x85\xd6\xe0Q@\x0cU\xf9\
-\x98\xcd\x0f\x1d\xc0q\x92\xb7p\xdf\x13\xfe\xf4\xab\x1bO\
-m\xa5\xa2V\x85\xe2\x04;\x13/\xf7\x94\x90\x12;O\
-_\xbc[\x11tr\x1f\xd0\x9cR\xdb7~\xd6,>\
-\xc78\xb6\x0d\x9eF\x8c\x8eb\x5c\xcfg\x94\x1b\x15\xbb\
-\x94g-\xf8\xb3O7\xfc\xe4O?\xe2\xcb\x8f7,\
-\xc1a[x0`1\xc0\xaf\xb3\x16\xf8k\xbf\xfbW\
-\xf0\xb7\xfe\xe6\xdf\xc0\xdf\xfa[\x7f\x0b\xbf\xf3[\x1f\xd4\
-f\xe6&h1:V
<\xadp\x8e\
-\x04\xcf\xdb\xbd\xe0\xf9\x96\xe8\xa8\xf1\x04\xf4\xf4\xc2\xa2>\
-\xe5B\xecqg`\xd2\x91\x0bAP\xad\x12F5F\
-\xb3\x1dZ7 \x0b\x1f\xb9\x10\xd4\x11\x18\x09\x05\x07\x93\
-\x85\xebA\xce\x5c\xeb\x1a:>\xddO\xfe\xbe\xb1\xb8\x1d\
-I\x91\xc4\x0dg\xc93\x1a\xda\x1a\x89\x90\xe5,[\xa3\
-\x9f\x1d\xdc\x9a;\x02\xd5\xbbH\xc5`\xf3\xe9\xf9\xeb?\
-\xfa\xcf\xfe>\x98\x13\xa4\xa9\xc9w\xef\x02|\xe7\x02\xe0\
-\xf5\xe9\x1f\x80\xfd\xbd\xdf\xfb\x7f\xfd\xf8\xda\xff\xf3\xff\xfb\
-\xf3n\x91%\xe4x92Rn\xd8\x16\x8f\xcb\xba`\
-Y<\xde?\x05Xp\xae\xb9-\x11\xdd\xd0\x8a&\xa3\
-)\xc3v\x1c7\xee\x5cy\x92K\xad\xc1\x82\x1b[\xaa\
-eF\x92\xd6Rg\xfa\x13C%\xf7\xf65\xbf\xfa5\xbf\xfa\xb5\xba\xfbk\
+\xf9e\xa6\xff9\xdb\xe8\xde\xd5\xd7.|\x19\xbf>w\
+\xde\x0doy\xff\xdd\xd9\xfe\xfa\x9f~\x0d~\x92\xe8\xcf\
+\xf9\x1e\x9f{\xfb\x9a_\xfd\x9a_\xfdZ\xdd\xfd\xb5\xfc\
+q\xe1\xd6\x0f\x00\xaf\xfd\xd0w\xfe!\xbe\xfb\x8b=\xe9\
+\xde\xf2\x0f\x8a?S\xbf\xb3\xf3\x13wt\xfd\xf5#\xbf\
+\xbb\x032\xf7\xda_\x8b\xd7pgW>\xc3\xe9]w\
+\xbe\x96\x1f\xf23\xf5\xdb\xb6\xf7\x5c\xbd\xf3\xea3\x5c\xf5\
+?4\xef\xb1\xff\xb5\xbf\x0eW_\xbbp\xf7}\x93\xee\
+-\x9f\xed\xf4k\xdf\xf9\x89;\xba\xfe\xfa\x91\xdf\xdd\x01\
+\x99{\xed\xaf\xc5k\xb8\xb3+\x9f\xe1\xf4\xae;_\xcb\
+\x0f\xf9\x99\xfam\xdb{\xae\xdey\xf5\x19\xae\xfa\x1f\x9a\
+\xf7\xde\x7f\xeb\x07\x80/+\xfc\x82\xbf\xe6\x8b\xe2\x99\xfe\
+\x87\xe7\xbd\xe9\xf7m\xef\xbd\xfa\x1c\xe9o\x9a\xed\xfdW\
+\x9e'<{\xda\xebw9>\xe1\xf7\xb6\xfe\xce\xbc\xb9\
+\xf2\xba\xf2\xcb\xfc\xf6\xf5\xbb\xc3\xa3\xefE\x7f\x9a\xbb\xf3\
+n\xf3\x96\xf7\x7f\xd9\xe1\xb3=\xfau\x0e\x9ey\xeb\xaf\
+\xf3\x15\xfd\xbe\xed\xbdW\x9f#\xfdM\xb3\xbd\xff\xca\xf3\
+\x84gO{\xfd.\xc7'\xfc\xde\xd6\xdf\x997W^\
+W~\x99\xdf\xbe~wx\xf4\xbd\xe8Osw\xdem\
+\xde\xf2\xfe\x89/\xf4\x07\x80\xe9\x17\xe0\xd1/\xea\xc4\xf4\
+Ey\xabo\xcf\x93\xe7v\x0co\xfd\x85\x89\xd7\xa3\x1e\
+\xdb[\xde\xf3]p\xf5\xeb\xd6\xf9\x15\x9f}\xf6\xd9\xf7\
+\xa3\xb7s\xf7\xf3NoL-oq\xefNl\xb6\x9d\
+'}z=G}\xeaML\xf3\x01\x0f\xd3\xf9\x87$\
+\xef\xe8\xb7\xbd\xc7\xfe\xe9k\xf2V\xdf\xed\xeb\x94\xdb1\
+Lox\x84x=\xea\xb1\xbd\xe5=\xdf\x05W\xbfn\
+\x9d_\xf1\xe3\xf8\xfb|c\xdb\xb9\xcdF\x9f^\xcfQ\
+\x9fz\x13\xd3|\xc0\xc3t~\xc5\xad\xbf\x04\xd87\xdc\
+Y\x16\x8d\xe7{\xc6\x1f\xae\xb5\x8f\xe0\xb9iv\xf3\xdb\
+\xe6\xb6/zn\xc7p\xe7\x1f\xf4\xed\x0d\xa1\xf7\xb5\xb6\
+\xdf\x17\xfc\x96\xd3\xdb\xaf\xb8\xa3\xef\xdd\x1f}\xf4\x83\x7f\
+t\xd2\x8b\x07\xf7\xe6wz#=n\xfc\x82\xe76\xee\
+h Z\xef\xe9\xb7\x90G\xe3w8\x0e\x8e!\xb5\xa9\
+\x0e\xf6j\xd2s\xdd\xef\xe0\xb6w\xc7\xce\xdb\xbf\xbd\x0c\
+\xb5\xbea\x9ai\xa2\xf1|\xcf\xf8=\xad}\x04\xcfM\
+\xb3\x9b\xdf6\xb7}\x9dr;\x86\xe7\xef\xf3\x9f\xfc\xdf\
+\xe7a\x8b!\xb5\xa9\x0e\xf4zgH\xcfu\xbf\x83\xdb\
+\xde\x1d;o\xff\xf6\xba\xe2\xf8\x03\xc0f\x1e\xb2`[\
+F\xce\x1d\x9d5[l\xff\xf6\xee\x99\xad\x1e\xa6Y{\
+7\xf4=\xe7\xd9;x~\xe2\xe4\xd3\xbd\xe4\xf1\xf2\x1b\
+\xec\x9d\xdc\xbd\xd0}\xdfa\xaa\xc1I\x0f\xdb\xfe\xd0\x9f\
+\xbb\xfb\xc0g\xeaC\x8f;\xc7\xdfh'\xff\x09\xfb9\
+\x06\xef\x08'm\xf2\x93~\xc23\xc11\xb8\xd6>\xde\
+\xe7\x9e\xeba\xda\xef\x19t!5\xea\xb9\xdb;X\x1f\
+z\x9e\xbc\xe7\xec\x1b\xda{\x8b\xed\xdf\xde=\xb3\xd5\xc3\
+4k\xef\x86\xbe\xe7<{\x07\xcfO\x9c|\xba\x97<\
+^~\x83\xbd\x93\xbb\x17\xba\xef;L58\xe9a\xdb\
+\x1f\xfasw\x1f\xf8L}\xe8q\xe7<\x7f\x9f\xff\xa0\
+\xe7z\x98\xf6{\x06]H\x8dz\xee\xf6\xde\x18\x7f\x00\
+\xb0Q\xf0\x22\xf0#Yv\xd2\x07\xfa\xe0\xdc\xb3\x93\x97\
+=\x13\xbb\x1e-5\xe7\x0d\x9e\x06\x1d=\xefm\x9fi\
+\xde\xb4G\xeb\xa77\xa5\xd6o8\x11M~*\xf7O\
+\xe6\xc1\xb3\xbd'=j\xeeM\xfb\xa8\xf5\x9brw\xaf\
+\xf1\x0ek\xc83O\xec\x83\xafI\x1d\xbc\xdbP\xa7\x87\
+\x1fq\xe8\xb9\xd6\xba\xdf^\xc4\xd4\x99\x01\xc7\x81\x99\xae\
+\x03>\xf6s\xbe}3\xa4\x1f\xa8\x93\x07\xf7\xac\x0d\xd6\
+\x13\xb7\x87\xe7\x9b\x9e\xcf}\xd2\x07\xfa\xe0\xdc\xb3\x93\x97\
+=\x13\xbb\x1e-5\xe7\x0d\x9e\x06\x1d=\xefm\x9fi\
+\xde\xb4G\xeb\xa77\xa5\xd6o8\x11\xcd\xf3\xf7\xf9\xf7\
+\xa0N\x0f?\xe2\xd0s\xadu\xbf\xbd\x88\xa93\x03\x8e\
+\x033]\x07|\xec\xe7\xfc\x8b\xfe}~\xe2\xf2\xdf\x00\
+\xb0\x88e^\xda\xcb\xacw\x0d\xe8S\xeb^h\x7f\xe7\
+a\xca=\xeb<\xb7\xf3p\x9a\x0f\x1d\xe3\x09\xc4]\x87\
+\xd4\xf0\xc8o^4\xd4<\xb3y\xb07\xe4f67\
+\xbd\xfcCD\xcf7t-7\x87|\x223\x01-9\
+w\xb0O\xe8\x1c\xa8s\xfa=\xdc\xa9w\xafu\xa1\xeb\
+\xfd\xb6\xd6\xb6o@\x1b\xac\x09\xdc\xe8\x99\xf5L\xe8\x1c\
+\xbd\xb5\x89}Bz9\xfe\xa6N\x8d\x18\x0fj\x9e\xb5\
+\x17\xa0\xb7n\x9a\xa5\x16\xda\x83yN\xb0&1\xf3x\
+YK\x0d\xe8S\xeb^h\x7f\xe7a\xca=\xeb<\xb7\
+\xf3p\x9a\x0f\x1d\xe3\x09\xc4]\x87\xd4\xf0x\xfe>\xff\
+\xc1\xce\x9c~\x0fw\xea\xddk]\xe8z\xbf\xad\xb5\xed\
+\x1b\xd0\x06k\x027zf=\x13:Gomb\x9f\
+\x90^\xce\x97\xed\xf7\xf9\xc4\xf8\x03\x80M&\xc3\xdc9\
+\xe9\x11\xd3\xe3\x11\xe4\x8187~\xd67\xd4Z\x1b\xf0\
+\xe6\x04\xe2\xc9\xab\xb1\xc6\xf3\x0d\x9e\x81\x9d\xd0u\xf7L\
+\xea\xd3\x9b&=5n\xe6N;\xec\x9d>\xb9\xb5\xa9\
+\xd9+\xf4\x0e\xfc\x93\x13\x07\xfaM\xea\xddk/\xfcr\
+\xf0\x0b[\x8e\x9e\x9b^\xc7\xae\x81g\xec\x0d\xee\xf9\xb8\
+N\x9c\x9b\xd8L\xb5\xcc\x85\xf4\xf0p\xcd\xa4N\x8f;\
+t\x8c\x87\xbf\xf1\xc3\xe4i\x92\xfb\x18\xd7\xf0\xd9\xbc\xd1\
+1\x93\x1e1\xbd\xd4\xa8\x03qn\xfc\xaco\xa8\xb56\
+\xe0\xcd\x09\xc4\x93Wc\x8d\xe7\x1b<\x03;\xa1\xeb\xee\
+\x99\xd4\xa77Mzj\xdc\xcc\x9dv\xd8;}rk\
+S\xb3W\xe8\x1d\xf8''\x0e\xf4\x9b\xd4\xbb\xd7^\xf8\
+\xe5\xe0\x17\xb6\x1c=7\xbd\x8e]\x03\xcf\xd8\x1b\xdc\xf3\
+q\x9d87\xb1\x99j\x99\x0b\xe9\xe1\xe1\x9aI\x9d\x1e\
+w\xe8\x18\x8f/\xe2\xf7\xf9\x89\xf5\xdf\x00\xd8\x18\xa3~\
+\xe4i9L>\xd4\xac\xe7\xe6\xa7&\xfcs{\x177\
+\xd0\xb7\x06\x98\x9fb\xe7\x9e\xcf\xa1f:\xbf\x03~x\
+6\xec\xdcp\xdf\xef\xcb\xe1==\xdf\xfa&uf\x81\
+\x9a}\xb9S\xe3L\xb5\xae'v\x1e\x92\x13s\x1b\xfa\
+S/5\xf7'\x0d\xfbzo N\xcf\xba\x9cIw\
+\xa7\x96\xb3\xedr\x9d8L;a\xf3\x83\xee\x91\x9f<\
+O\xbd\xd4\xa8\xbbo_\x98<<\x0f\x93\x0f5\xeb\xb9\
+\x9f\xbf\xcf\x7f\x80\xfb~_\x0e\xef\xe9\xf9\xd67\xa93\
+\x0b\xd4\xec\xcb\x9d\x1ag\xaau=\xb1\xf3\x90\x9c\x98\xdb\
+\xd0\x9fz\xa9\xb9?i\xd8\xd7{\x03qz\xd6\xe5L\
+\xba;\xb5\x9cm\x97\xeb\xc4a\xda\x09\x9b\x1ft\x8f\xfc\
+\xe4y\xea\xa56\xd5\xcd\xf8\x03\x00C\x188\x0f~\x98\
+\xe9\xdc\xf0\xc8\x9c\xd6\xd9\xdf1\xb7c\xef&\xa6\x1f\xda\
+\xdb\xe0\xc5\xac\xfd\xc0=r\xe6\xc8\x81\x1a8o\xbd=\
+\x80
\xcc'\xde\xe6\xa3\
+\xe9\xf7x\xce\xb7u=\x13\x0d^9\xe4\xc6uz}\
+\x07\xfa\xd1\xb2;\x10\xd3\xf3\x8ca\x9e\xd8s\x81\xbco\
+\xcf\x5cq\xfc;\x00^\xba\x99s\xa7\x9f\x98\x83\x1e\x92\
+\xfbx\x8e\x9c\x1awp\xec9\xdf\xd4\xf1j\xbf\xd0u\
+\xe2@\x9eC\xce\xff2\xe9\x19h=:\xea\xf4\xa8\x9f\
+\xc0\x1f\x1d>@\x1d_\xf2\xe0=\x01\x9fi\xdePC\
+\x8b/\xb7\x99\xe6\x991\xce\xedG\xdc\x07\x1c[\x0b\xae\
+\xf5\xbfz\xa3\xe7\xd8\x07&]\x9849\xc4\xb9\x031\
+yp\xcc\x5c\xebr\xdb\xa7o\xeb\xadk\xd0t\x1c<\
+\x97\x98\x03\xe4\xd1P\xef\xbe\xbdC\xeb\xb8\xf1\xe0\xa0\x87\
+\xe4>\x9e#\xa7\xc6\x1d\x1c{\xce7u\xbc\xda/t\
+\x9d8\x90\xe7\x90?\x7f\x9f\xff\x80i\x9e\x19\xe3\xdc~\
+\xc4}\xc0\xb1\xb5\xe0\xda\xf3\xf7\xf9\xe7\xe3\xe0\xb9\xc4\x1c\
+ \x8f\x86\xba\xfb\x13\xe3\x0f\x00^\x8c!\x10\xbb\xc6\x92\
+\xaeM\xcb\xad\xcd\xb1\x86\xdc>\x8f\xd2;\xf3\x0f\x12\xb5\
+\xee\x85~\x07\xfb9\x86\x1e$\xa7\xe6ynk{\xee\
+\xa3\x8f>\xfa\xdc\x5cb\xe7\xa1\xf3@\x9e\xdb\xfd\xdc\xd4\
+\x9cw-$\xa7\x16\x5cGO\xad{\x06-lZ\xeb\
+r;6\xd1\xf5\x9co\xf4\xd6\x11\xbb\x16\xa6}\xc65\
+\xcf\x015\xee\xe8\xd9A\x1c\x5c\xc3\x93Z\xe3:\xb1}\
+\x81\x9a\xef\x80\x8ez\x83\xce\xb4\x0eMnN\xf0\x9e`\
+\x1d\xe0\xd5\xb5\xe9-\xd6\xe6XCn\x9fG\xe9\x9d\xcf\
+\xdf\xe7\x9f\xaf\x85\xe4\xd4\x82\xeb\xe8\xa9u\xcf\xa0\x85M\
+k]n\xc7&\xba\x9e\xf3\x8d\xde:b\xd7\xc2\xb4\xcf\
+\xb8\xe69\xa0\xc6\x1d=;\x88\x83kxRk\x5c'\
+\xb6/P\xf3\x1d\xd0Qo\xd0\x99\xd6\xa1\x99\xb4\xe6\xf8\
+\x97\x00\x03\x8f\xe0l\xb8\xe7\xe5\xd4\xb9\xbb6i\xc0\xb9\
+=\xb9\x99\xef\xbc}\x5cK~\xc4\x1bW=\x0ey\xd8|\xbb\x9f\x9b\
+w\x13s\xee\xd2\xfa\xc4\xf8\x85\xc4\xce\xaf@\xd7\xf3\xa1\
+\xbd'\xd2\xe30\xe7yn\xfa\xae\x99m\xd63\xc1u\
+\xe8~N\xfa\xd6\x04{\xd3o\x8dq\x8f\x1d\xcc\x06\xee\
+\xaeM\x1apnOn\xe6;o\x1f\xd7\x12O\x9ap\
+\xaa1g\x9c\xbbo\x9f\xc4\xad\x0b\xa9\xdb\xdb$\xb7\x07\
+9^\xf60=g\xa8\xbb\x8f\x1f\xf1\xc6U\x8fC\x1e\
+6\xdf\xee\xe7\xe6\xdd\xc4\x9c\xbb\xb4>1~!\xb1\xf3\
++\xd0\xf5|h\xef\x89\xf48\xccy\x9e\x9b\xbekf\
+\x9b\xf5Lp\x1d\xba\x9f\x93\xbe5'\x8e\x7f\x09\x103\
+\x96\x90\x87\xe9\x11\xdd\xf3lH\xee\xb9`Mn\xeb\x1d\
+\x03\x1e\xf8t\x0e\xbd7\x9c\xfc\x02\xfb\xa9Q7\xee\xe5\
+\xa0\xdf\xb0_\xd8fZ\x03hs\x07z\xc9]\xb3\x8e\
+\xba\xfb\x818\x0e\xd1\x18\xf49\xe9\xf1\x07#\x07\x8d\xd9\xf2\
+\xf6\x06\xfc\xc1\xba\xd4\x93\xd3\xb7n\xa3\xe7'\x5c\x7f\xfe\
+>\xffA\x0d\xa8\xe5\x84\xd3{\xd3\xb36\xd8{\xbaC\
+\xef\xcf\xa1\xe6\xdb'\xb4\x0eO\xe2\xd6r\xe8\xe7\xd0C\
+\xc7\x0c\xbd@\x0d\x0d=r\xf4\x9e\x09\xd4\xba\xdf:p\
+?\xa7\xe7\xc8\xa15\xee\xa5\xde\xf3\xc1q\x88\xc6\xa0\xcf\
+I\xef\xc7\xe1\xf79\x8c?\x00\xf4\xa3\xc9\xbd\x84\x98\x9b\
+:w`\x0e<\x0fh\xeca\xcf\xa9\xdew\xb0\x86\x9b\
+\xfe\xa6\x01\xea\xc1\xf3\x8d{\xf6\xe2\xa4\xd6?E&\xe6\
+\x04\xea\x81\x1a}|\xa8\x11Ou\x0eyn\x83>\xe4\
+M\x13\x99\xe1\xc0\xe4I\xdc:p\xdcx&\xe0\xd3~\
+\x9d\x07\xf2\xd6\xb1\x8f\x9bZ\xcf\x1b4\x1cp\xdc\xde\xf6\
+{$f\xd6^\xdc\xd6\x87\xad\xb6\x11-\xde\xde\x11\xa6\
+\x9a\xbd\xa9S\xdbr|\x1csS\xe7\x0e\xcc\x81\xe7\x01\
+\x8d=\xec9\xd5\xfb\x0e\xd6p\xd3\xdf4@=x\xbe\
+q\xcf^\x9c\xd4\x9e\xbf\xcf?\x8fg\x02>\xed\xd7y\
+ o\x1d\xfb\xb8\xa9\xf5\xbcA\xc3\x01\xc7\xedm\xbfG\
+bf\xed\xc5m}\xd8j\x1b\xd1\xe2\xed\x1da\xaa\xd9\
+\x9b\xbak\x1b\xc7\xbf\x03\x10#\x96q\x5c\xf3\x1d\xb8\xdd\
+kR\xe74\x9e\x9f\xa0\xee\x9d\x8d5a\xd2M\xfe=\
+\x07\xcc\xdb\xc7\xde\x93\xbe\xeb\xd3l\xc3\x0c\x07\x98\xa5~\
+\xc7\xcb\x1e\x9e\x07\xf7C4\xde\xdflZ{\x13s\x07\
+\xcf%&w\x0c\x9e\x0b\xc9]\xeb\x1c\xfa_A\x87\xc4\
+\x93\xbe5\xbe'oj\x9e\x83\xc9+\xf4[\xc89\xde\
+c]p\xee\xd8\x1e\xce\xf1\xea~\xf7\x9a\xd4\xa8\xa3\xcd\
+\xc1\xa3k\xbe\x03\xb7{M\xea\x9c\xc6\xf3\x13\xd4\xbd\xb3\
+\xb1&L\xba\xc9\xbf\xe7\x80y\xfb\xd8{\xd2w}\x9a\
+m\x98\xe1\x00\xb3\xd4\xefx\xd9\xc3\xf3\xe0~\x88\xc6\xfb\
+\x9bMkob\xee\xe0\xb9\xc4\xe4\x8e\xc1s!\xb9k\
+\x9d\xc3\xf3\xf7\xf9\x0f\xf7\xbb\xd7\xa46\xd5\xcd\xfaw\x00\
+\xb8Y\x82\x11\xbd\xe4\xd6\xf9\x0e\xccAr\x8e\xf3\xd0:\
+r\xd7'\xac\x0dS\xce\x0en\xb0\xae\xf7Y{\x9a\xb3\
+\xb7\xe3f\xaaA\xfcr\xd0\xb4?\x07\x5c\xeb\xd9@\x8c\
+\xcf\xa6k\xd0\x01Z\xcf\xdbc\x8b\x83\xeb\xe0x\x82\x99\
+\xcd'\xb1{\xf8M\xff\xab\xe7\xa4\xb7'X\xeb;\xc7\
+\xba\x13\x9e\xf3.\xea@\x8d:73\xb9\xbb\x97\xbb\xdf\
+\x81\xae\xe7\x81\xba\xb1_\xdf9\xf1\xc0\x87\x1e{B\xdf\
+\x819H\xceq\x1eZG\xee\xfa\x84\xb5a\xca\xd9\xc1\
+\x0d\xd6\xf5>kOs\xf6v\xdcL5\x88_\x0e\x9a\
+\xf6\xe7\x80k=\x1b\x88\xf1\xd9t\x0d:@\xeby{\
+lqp\x1d\x1cO0\xb3\xf9$v\x0f\xbf\xe7\xef\xf3\
+\xcf\xcf\x03uc\xbf+n\xfd\x1d\x00? \x90\xe71\
+\xfd\xa0\xb0\xd5\xa8O^\xc4hrS'\xa6w\x82\x19\
+\xe8\x19\xef\xb2\xd6\xfb\xc2\xd4\xeb\x99\x86]\x93\x8f\xdf\xe1\
+\x18\xcf\xd4\xd8\xd3\xd0\xf3\x5c`\xd6L>\xe8\xban?\
+z]\x0b\xcc\xdb#\x87\x1e\xb8\x1e\x1c7\xf1\xf1\xae\x8d\
+\xf6\x0c\xd4\xa8\xe7\xb6W\xe7\x01\xad\xdf\xcf\x1b\xd0\xf6L\
+\xf0\x9c\x99\xb4\xd4\xa6\xfdW\xb0\x87\xbb\xf1{\x13;\xa7\
+\x7f\x02\xedI\x8f/\x90{\xcel\xb5i\x87\xbd\xf1\x0c\
+\xb9\xa9\x13\xd3;\xc1\x0c\xf4\x8cwY\xeb}a\xea\xf5\
+L\xc3\xae\xc9\xc7\xefp\x8cgj\xeci\xe8y.0\
+k&\x1ft]\xb7\x1f\xbd\xae\x05\xe6\xed\x91C\x0f\x5c\
+\x0f\x8e\x9b\xf8x\xd7F{\x06j\xd4s\xdb\xab\xf3\x80\
+\xd6\xef\xe7\x0dh{&x\xceLZj\xd3\xfe+\xd8\
+\xc3\xdd\xf8\xbd\x89\x9d\xd3?\x81\xf6\xae\xfe\xf6_\x02\x9c\
+\xe0\x81\x13y\x00\xbd\x8e\x1b\xd7\xd0\xd9w\xaa\x05\xfbn\
+\xa4\x8f\x7fn\xc7\x10\xcd\xc9\xe7jG\xe8\xb7\xf4\x1ez\
+\xe8&\xcf\xa9\xd6z\xfc\xa0\xf3\xcd;t\x9d\xdc3\xd6\
+\xb4\x9e\xb7x'\xb1\xef\xae\x05{\xa5Nn\xcd\xa6\x87\
+M\x1b&\xbdAo]b\x0e9\xa0\xcf\x9dC\xafs\
+\xe8Z\xe2\xd4\x02w`\xde=\xf7a\xaa\xc7\xb3wt\
+-x\x96\x9e\xb5\xd3\xbe\x13\xccM\xc4\x8b^\xc7\x8dk\
+\xe8\xec;\xd5\x82}7\xd2\xc7?\xb7c\x88\xe6\xe4s\
+\xb5#\xf4[z\x0f=t\x93\xe7Tk=~\xd0\xf9\
+\xe6\x1d\xbaN\xee\x19kZ\xcf[\xbc\x93\xd8w\xd7\x82\
+\xbdR'\xb7f\xd3\xc3\xa6\x0d\x93\xde\xa0\xb7.1\x87\
+\x1c\xd0\xe7\xce\xa1\xd79t-qj\x81;0\xef\x9e\
+\xfb0\xd5\xe3\xd9;\xba\x16H}\xf3d\xa6oh\xcf\xe4\xad\x09\xdb|\x93\xbe\
+\xdf\xb2\xf9E\xd3\xba\x89\xcdk\xf3\xa4\xee\xb9\x0dkN\
+\xb3\xde\x95\xb8\xe7&<\x83&\xb5\xde1\xd5\xee\x10\xed\
+\xd5n\xf7\xa95[\x1d\xd6\xbf\x04\xd8\xcb\x93\xfb\xc3L\
+\xd0\xb3\xc6^\xccO\xfe'N;7z\x86\xf7\x137\
+\xeeC\xbfs\x9b\x9f4@\xaf\xeb'z&\xf9\xb4\x93\
+Z\xebsw/w\xea\xf64\xed\x01\xad\x0b[\xcd\xfe\
+\xd0ypm\xdb\xdb\x1at\xde\xed\x9d\xc4\x0dz\xf7\x88\
+\xb9\xa3\xb1\xaf\xebW\xb4\xef\xb4\xaf\xfdC\xd7\xac\x0f\xd3\
+L\x88\xae\xb5\x10}\xf7\xdb\x83\x1e\xfe\xdd\x9f<\x1az\
+\xbd\x07/\xe6'\xff\x13\xa7\x9d\x1b=\xc3\xfb\x89\x1b\xf7\
+\xa1\xdf\xb9\xcdO\x1a\xa0\xd7\xf5\x13=\x93|\xdaI\xad\
+\xf5\xb9\xbb\x97;u{\x9a\xf6\x80\xd6\x85\xadf\x7f\xe8\
+<\xb8\xb6\xedm\x0d:\xef\xf6N\xe2\x06\xbd{\xc4\xdc\
+\xd1\xd8\xd7\xf5+\xdaw\xda\xd7\xfe\xa1k\xd6\x87i&\
+D\xd7Z\x88\xbe\xfb\xedAo\xf26\xeb\xbf\x01\x98\x96\
+\xf3\xd8\xa9\x07\xe9Yc\xafm\xbe\xf3&3\xc1^0\
+\xd5&\xa2\xc1\xc7\xf0&\xb0W\xfb\xf2v\x0e8G\xd3\
+\xb0\xa3{\x9365\xdeE\x7f\xd2\x05\xd7\xd9\xc1\xdd\xb4\
+'$\xcf\xa1\x7f\x05zC\xeeybz\xd3\xdcF\xbf\
+c\x9b\xf3\x9bs\x9ft\xc1oA\xdf3h\xcdT\x0b\
+\xf6\xed\xb8}a\xaaO\xfe\xd1\xb5\xd6;\x80x\xaa\x05\
+\xc7\x9e\xe74\xd1\x9c\xde\x1f\xd2\xb3\xc6^\xdb|\xe7M\
+f\x82\xbd`\xaaMD\x83\x8f\xe1M`\xaf\xf6\xe5\xed\
+\x1cp\x8e\xa6aG\xf7&mj\xbc\x8b\xfe\xa4\x0b\xae\
+\xb3\x83\xbbiOH\x9eC\xff\x0a\xf4\x86\xdc\xf3\xc4\xf4\
+\xa6\xb9\x8d~\xc76\xe77\xe7>\xe9\x82\xdf\x82\xbeg\
+\xd0\x9a\xa9\x16\xec\xdbq\xfb\xc2T\x9f\xfc\xa3k\xadw\
+\x00\xf1T\x0b\x8e\xa7\xf9\x89\xdb\xff\x06`2o<\xe7\
+\xbb\xf5\xc9\xe3\xd7\x8f\xef\xbc\xd9\xbc\xf0\x83\xc4\xe8|\xa3\
+\x99\xbc\xa9\xa1\xdfH\x9f\x03\xce\xbd;x\x97{\xd3\x1b\
+B\xcf'\xa6\xc6Ln\x0euzw\xb0\x7fH\xde\xb5\
+`_\xf7\x89\xbd\xb3k\xc9{67\xa7\x99j\x10\x9f\
+\xf4\xf1\xf3^\xc7'\xfc\x16\xbf\xc1qh\xbf\xcd\x9f\xba\
+}\xc1\xde`\x9f\xd4\xaf|\xc1\x1e\x90\x9a\xeb\xc4\xd4\xb7\
+\xbe\x99t\xa1\xdf9\xe19\xdf\xadO\x1e?{Ny\
+\xb3y\xe1\x07\x89\xd1\xf9F3ySC\xbf\x91>\x07\
+\x9c{w\xf0.\xf7\xa67\x84\x9eOL\x8d\x99\xdc\x1c\
+\xea\xf4\xee`\xff\x90\xbck\xc1\xbe\xee\x13{g\xd7\x92\
+\xf7lnN3\xd5 >\xe9\xe3\xe7\xbd\x8eO\xf8-\
+~\x83\xe3\xd0~\x9b?u\xfb\x82\xbd\xc1>\xa9_\xf9\
+\x82= 5\xd7\x89\xa9o}3\xd5\xcc\xf1\xef\x00\xf4\
+\x871\xe9qL\xe7a\xaa\xf9\xf1}\x87\xde\x07\xd3\xbe\
+\x9c\xd6o;\xd1\xd2\x9f\xe6\xbb\x86\x16:7\xfd\x0e\xe7\
+\xdd\xeb\xbd!y\xfbw-9\xc7\xf9\xe9]\x10\x0d\xba\
+)&\x0f\xf8\x07\xd7\x83\xf7\x039Zk\xa8\xd9'q\
+\xfbNxO\xf4\xce\x13\xb7\xc7\xe4\xdb\x1e\xdd\x07\xebB\
+\xe7\xc0\xde\xad?\xedw\x8d\xb9\xed\x1dxO\xfd\xd4|\
+\xccI\xdfPs\xaf?\x0f\xb3=\xdfy\x98j\xf1\xc3\
+\xb3\xef\xd0\xfb`\xda\x97\xd3\xfam'Z\xfa\xd3|\xd7\
+\xd0B\xe7\xa6\xdf\xe1\xbc{\xbd7$o\xff\xae%\xe7\
+8?\xbd\x0b\xa2A7\xc5\xe4\x01\xff\xe0z\xf0~ \
+Gk\x0d5\xfb$n\xdf\x09\xef\x89\xdey\xe2\xf6\x98\
+|\xdb\xa3\xfb`]\xe8\x1c\xd8\xbb\xf5\xa7\xfd\xae1\xb7\
+\xbd\x03\xef\xa9\x9f\x9a\x8f9\xe9\x1fa\xfd7\x00'\xb2\
+$\x1a\x0eK\xa9\xf7C\xae\xfc\xc2\x1dM@\x87\xbf\xe7\
+\x5c\xcb\xf1\x1bL\xea\xf4\xd1\x06\xee\xe0y\xd7\x83{\xbd\
+\xc3\xf5M\x13\xe2\xd1\xbe\xd0\xf5\xcc\x9f\xf4\xec\xda\xfa\x13\
+\x93'9\xef\xb5\xa7u'\xf0\x98\xb0\x9f\xf7\xb3\xaf\xe9\
+\xfa\xe6\xdd\x9ea\xd2\xfd\xff\xdby\x7f]\xeb\xb3\xedL\
+\xabU\xd8-u\x84Dd\x1c\xb83rB\xee\x8b[\
+\xe0\x06\x10\x01y\xdf\x00\x22AdHD\xad\x96L\x88\
+\x84D@`\xacF\xdc\x00\xd8.\xa8\xb7\xcfy\xba\x9e\
+\xf3\x9e1\xe6o\xae\xb5\xf7Wn\xdb\xeb\x91\xa6\xe6\xf8\
+\xf3\x8ew\xcc\xb5\xbeo\x1f\xef\xae*5X\xef\xfb\x89\
+\xe9=\x1bS/5\xef\xcci\x1d\xb9\xb5\x13\xe9s\x0c\
+s\x9e\xb5\x8e\xfa\xb4\xbbA\xc3\xe9\xd9\xdc\xd4\xc2\x93_\
+\xb8\xd1\x04t\xf8{\xce\xb5\x1c\xbf\xc1\xa4N\x1fm\xe0\
+\x0e\x9ew=\xb8\xd7;\x5c\xdf4!\x1e\xed\x0b]\xcf\
+\xfcI\xcf\xae\xad?1y\x92\xf3^{Zw\x02\x8f\
+\x09\xfby?\xfb\x9a\xaeo\xde\xed\x19&\x1dX\xef\xfb\
+\x89\xe9=\x1bS/5\xef\xcci\x1d\xb9\xb5\x13\xe9s\
+\x0cs\x9e\xb5\x8e\xfa\xc9;\x8c\xbf\x00<\xd1K\xc8}\
+[\xf3\xf4\x88p\xa3\x81h\xf1\x0f\xbd\x1f\xfc\x06\xee\xd4\
+\xacO\x8d\x03\xeeO\xb4\xdfD\xea\x93O\xef:\x81n\
+\xdb\x01O}\xef\xe3]9]\x07z\xae\xdd0}\xae\
+\xd4\xf0\xea\x1d\xb0\xedq}\xf2\x0e\xae\xa3o\xbfi6\
+\x1a\xeby\xe7\x89'\xdf\xa7\xf9\xe0\x9d\xec\x85\x9b\xf9\xf0\
+\xf4\x0e\xbc\x9b\xe8\xa8O\xfd\x06\x0d\xfe=\x9b\xdb\x9a\x9b\
+\xf7\xdfh\xc0\xef\x0d\xbd\x1f\xfc\x06\xee\xd4\xacO\x8d\x03\
+\xeeO\xb4\xdfD\xea\x93O\xef:\x81n\xdb\x01O}\
+\xef\xe3]9]\x07z\xae\xdd0}\xae\xd4\xf0\xea\x1d\
+\xb0\xedq}\xf2\x0e\xae\xa3o\xbfi6\x1a\xeby\xe7\
+\x89'\xdf\xa7\xf9\xe0\x9d\xec\x85\x9b\xf9\xf0\xf4\x0e\xbc\x9b\
+\xe8\xa8O}s\xfc\x05\xe0i\xf8\xa9\x1f\xa2\xb1\x8e\x0f\
+q\xfb%L\xf4\xde\xaf|\xa17\x9f\xa1\xe13M\xb3\
+\xaeM\xef\xda\xe66\xed-'\xcf\xedM\xa9O{\xc3\
+\xed\x1b\xcd4\x93\xdaT\x87'O\xd8\xdez\xf2\x86\x1b\
+\x8d\xb9}S3\xed9y\xa5\xe7\x99\x9eO\xfe\xca\xdb\
+\x9f\xde\x8dW\xeb\x9ev\xdc\xbc\xa1\xdf\xca\x8e\xa77\x9d\
+\xe8\xbd\xb7^\xd3\xdc\xcdgh\xf8L\xd3\xack\xd3\xbb\
+\xb6\xb9M{\xcb\xc9s{S\xea\xd3\xdep\xfbF3\
+\xcd\xa46\xd5\xe1\xc9\x13\xb6\xb7\x9e\xbc\xe1Fcn\xdf\
+\xd4L{N^\xe9y\xa6\xe7\x93\xbf\xf2\xf6\xa7w\xe3\
+u\xf3\xf9\xbe\xf4O\x00\xbe\x93W\x1e\xdd\xfc\xfc\xf3\xcf\
+\xbf\x8ff\xb6\xf7R\xcf\xfd#?\xd3\x13\xef|\xe6w\
+y\xf5s\xde\xbc\xedG|w\xe1\xdd\xef\xe5\x9d\xb9\xe9\
+\xef\xc0\xf6\xb9\xf0\xff\xeawy3\x9f\x99\xa7\xcf\xf3\xea\
+;n\xf9\x11\xbex\xbe\xf3g\xf4\xf99\xbf\xe7\xd5\xcf\
+y\xf3\xb6\x1f\xf1\xdd\x85w\xbf\x97w\xe6\xa6\xbf\x03\xdb\
+\xe7\xc2\xff\xab\xdf\xe5\xcd|f\x9e>\xcf\xab\xef\xb8\xe1\
+\xad_\x00\xcc\xed\x97\x09\xf4\x9ft\xd3\x97\xf1\xf4\x05M\
+\xbc2\xf3#\xbe\xe0[~\xc4\xee\x9b\xef\xb85\xa7\x99\
+\xdf\xfa\x8d\xaf\xbc\xed]\xecI\xfc\x9d{\xde\xf5\xca\x9f\
+\xcd\xab\x7f\xdf\xb7]]\x7f\xe7M\xafz\xd0\x7f\xd2M\
+\x9f\xf1\xd5\xcf\x1d^\x99y\xe7\xf3\x7f\x17?b\xf7\xcd\
+w\xdc\x9a\xd3\xcco\xfd\xc6W\xde\xf6.\xf6$\xfe\xce\
+=\xefz\xe5\xcf\xe6\xd5\xbf\xef\xdb\xae\xae\xdf\xbc\xe9\xad\
+_\x00n\x1e\xcc\xf2\xd3#&\xcd\xcd\xa3[\xd3\xef\xe9\
+\xfc\xe6\x0d\xcd\xcd;\xe0\xd5?\xc0\xe6\xf63\xbf\xf2\xa6\
+\xf0\x1d\x9f\xe1\xc6\xe3\xf4\xf9\xe9\xd9\x87\xf8\x9d\xf7M>\
+\xcdm\x9d?\xe7\xbf\xd6z\x0e\xe8\xf5\xceIg\x1fk\xac\xed\
+\xb9\xe0\x99\x80On\xe2\x89\xad\x1e\xd2;\xf5\xc3K\xff\
+\x04\x00\xa6\xb8\x1f\xd9\x8b\xc9\xdb/\xb7\x7f#\xef\xb9`\
+=l\xb5i>t\x9dw\x184\xd4\xb9\xad\xf5=\xf5\
+\x83\xeb\x1cr\xcf\xe5\xa6\x17\x5c'f\x86\x18\x1c\xdf\xd2\
+\xfe>\xd0\xfb\xdc\xef